Search code examples
c#reflectionlambdadelegatesmethodinfo

correct signature to use in getmethod on class with multiple overloaded generic methods requiring delegate argument


Following an answer fulfilling the question in part here is some additional information to hopefully solve the points still at issue

Start edit

var curEntityPI = ctx.GetType().GetProperties().Where(pr => pr.Name == "Client").First(); Type curEntityType = curEntityPI.PropertyType.GetGenericArguments().First(); Type[] typeArgs = { curEntityType }; Type propertyManagerType = generic.MakeGenericType(typeArgs); var propertyManager = Activator.CreateInstance(propertyManagerType, new object[] {});

with this in mind i can't use the closeMethod.Invoke in the same way displayed in the first answer and it is the Func and return body that I don't know how to put in place when invoking

End edit

What should the method signature look like to reflection, I'm trying to invoke the equivalent of this

DynamicPropertyManager<ThreeColumns>.CreateProperty<ThreeColumns, string>(
     "Four",
     t => "Four",
     null
  ));

on this class found here http://putridparrot.com/blog/dynamically-extending-an-objects-properties-using-typedescriptor/

  1. But I'm trying to do it using reflection. What I'm struggling with the most is getting the correct method overload.

  2. I have to be honest though I'm also not totally sure how to supply the correct argument for the lambda bit through reflection either.

I was going to try this in part but don't know what the func bit would look like when doing MakeGenericMethod

Func<string> funcArg = () => { return "Four"; };

object[] args = { fieldOrPropertyName , funcArg, null };

The class contents from the link above are included for reference.

public class DynamicPropertyManager<TTarget> : IDisposable
{
    private readonly DynamicTypeDescriptionProvider provider;
    private readonly TTarget target;

    public DynamicPropertyManager()
    {
        Type type = typeof(TTarget);

        provider = new DynamicTypeDescriptionProvider(type);
        TypeDescriptor.AddProvider(provider, type);
    }

    public DynamicPropertyManager(TTarget target)
    {
        this.target = target;

        provider = new DynamicTypeDescriptionProvider(typeof(TTarget));
        TypeDescriptor.AddProvider(provider, target);
    }

    public IList<PropertyDescriptor> Properties
    {
        get { return provider.Properties; }
    }

    public void Dispose()
    {
        if (ReferenceEquals(target, null))
        {
            TypeDescriptor.RemoveProvider(provider, typeof(TTarget));
        }
        else
        {
            TypeDescriptor.RemoveProvider(provider, target);
        }
    }

    public static DynamicPropertyDescriptor<TTargetType, TPropertyType>
       CreateProperty<TTargetType, TPropertyType>(
           string displayName,
           Func<TTargetType, TPropertyType> getter,
           Action<TTargetType, TPropertyType> setter,
           Attribute[] attributes)
    {
        return new DynamicPropertyDescriptor<TTargetType, TPropertyType>(
           displayName, getter, setter, attributes);
    }

    public static DynamicPropertyDescriptor<TTargetType, TPropertyType>
       CreateProperty1<TTargetType, TPropertyType>(
          string displayName,
          Func<TTargetType, TPropertyType> getHandler,
          Attribute[] attributes)
    {
        return new DynamicPropertyDescriptor<TTargetType, TPropertyType>(
           displayName, getHandler, (t, p) => { }, attributes);
    }

    public static DynamicPropertyDescriptor<TTargetType, TPropertyType>
       CreateProperty<TTargetType, TPropertyType>(
          string displayName,
          Func<TTargetType, TPropertyType> getHandler,
          Attribute[] attributes)
    {
        return new DynamicPropertyDescriptor<TTargetType, TPropertyType>(
           displayName, getHandler, (t, p) => { }, attributes);
    }
}

Solution

  • Reflection and generics are working very well together, but how to approach a specific goal is very context dependant, because of possibly closed, open and partially closed types and methods. Nonetheless often it is easy to get what you are looking for by using Linq. Have a look:

    // get type from somewhere
    var compileTimeUnknownType = Type.GetType("ThreeColumns");
    
    if (compileTimeUnknownType == null)
        throw new ArgumentException("compileTimeUnknownType");
    
    var managerType = typeof (DynamicPropertyManager<>).MakeGenericType(compileTimeUnknownType);
    
    var createPropertyMethod = managerType.GetMethods().Single(x =>
    {
        var p = x.GetParameters();
        var g = x.GetGenericArguments();
        return x.Name == "CreateProperty" &&
                p.Length == 3 &&
                g.Length == 2 &&
                p[0].ParameterType == typeof (string) &&
                p[1].ParameterType == typeof (Func<,>).MakeGenericType(g) &&
                p[2].ParameterType == typeof (Attribute[]);
    });
    
    var closedMethod = createPropertyMethod.MakeGenericMethod(new[] {compileTimeUnknownType, typeof (string)});
    
    var paramExpr = Expression.Parameter(compileTimeUnknownType, "arg");
    var lambda =
        Expression.Lambda(typeof (Func<,>).MakeGenericType(new[] {compileTimeUnknownType, typeof (string)}),
            Expression.Constant("Four"), new List<ParameterExpression>() {paramExpr}).Compile();
    
    var ret = closedMethod.Invoke(null, new object[] {"Four", lambda, null});