Invoke a method from a generic interface with a parameter of a result of another generic method

时光总嘲笑我的痴心妄想 提交于 2019-12-13 00:09:44

问题


I'm trying to make a class which binds all classes which inherit a certain interface to be executed in an event fired by a custom entity framework model builder.

What I have:

1) A generic interface IOverride which has a method Configure(EntityTypeConfiguration entity)

2) Several classes that implement the interface.

public class ItemOverride : IOverride<Item>
{
    public void Configure(EntityTypeConfiguration<Item> entity)
    {
        // Do something with entity
    }
}

3) A method which gathers all classes which define the interface and combines them into a list of IOverride's like this:

var list = (from x in assembly.GetTypes()
                from z in x.GetInterfaces()
                let y = x.BaseType
                where
                    (y != null && y.IsGenericType &&
                     typeof (IOverride<>).IsAssignableFrom(y.GetGenericTypeDefinition())) ||
                    (z.IsGenericType &&
                     typeof (IOverride<>).IsAssignableFrom(z.GetGenericTypeDefinition()))
                select z).ToList();

4) I try to follow that up with invoking the method Configure in an event...

var method = typeof (IOverride<>).GetMethod("Configure")
var entityMethod = typeof (DbModelBuilder).GetMethod("Entity");
foreach (var item in list)
            {
                var target = item.GetGenericArguments().Single();
                var invoked = entityMethod.MakeGenericMethod(target).Invoke(args.ModelBuilder, new object[] {});
                var func = method.MakeGenericMethod(item);
                ModelCreating += (o, eventArgs) => func.Invoke(invoked, new object[] {});
            }

However, when running the actual event, I'm getting a

Additional information: Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.

Exception on the func.Invoke() line. I'm clearly doing something wrong, but I'm not 100% sure what it is. I'm thinking maybe Reflection is confusing me when I'm feeling under the weather or maybe I just did something incredibly stupid. Anyway a nudge in the right direction could suffice.


回答1:


The problem is that you are getting method from IOverride<> and not from real type. So it hasn't references to inheritor. And also when you call func.Invoke you should pass instance of inheritor of IOverride<>, and now you are passing EntityTypeConfiguration<T> that you get in invoked variable. But this variable should go as parameter.

Here is working example.

var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
var builder = args.ModelBuilder;
foreach (Type x in assembly.GetTypes())
{
    foreach (Type z in x.GetInterfaces())
    {
        Type y = x.BaseType;
        if ((y != null && y.IsGenericType && typeof(IOverride<>).IsAssignableFrom(y.GetGenericTypeDefinition())) || 
            (z.IsGenericType && typeof(IOverride<>).IsAssignableFrom(z.GetGenericTypeDefinition())))
        {
            // first difference - we get Configure method from real object, and not from IOverride
            var method = x.GetMethod("Configure");

            var target = z.GetGenericArguments().Single();
            var invoked = entityMethod.MakeGenericMethod(target).Invoke(builder, new object[] { });
            var func = method.MakeGenericMethod(typeof(string));

            // this one block can go to ModelCreating event as in your example,
            // but locally i didn't use it

            // second difference - we create instance of original type
            var obj = Activator.CreateInstance(x);
            // third one difference - we pass instance as `this` and pass invoked as parameter
            func.Invoke(obj, new[] { invoked });

        }
    }
}


来源:https://stackoverflow.com/questions/21701054/invoke-a-method-from-a-generic-interface-with-a-parameter-of-a-result-of-another

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!