C# Reflection: How to use an “object” as a “type-p

2019-07-28 05:15发布

问题:

I have this domain:

public class GenClass<T> { }

public class Type1 { }

public class Type2 { }

public class GenType1 : GenClass<Type1> { }

public class GenType2 : GenClass<Type1> { }

public class GenType3 : GenClass<Type2> { }

public class GenType4 : GenClass<string> { } 

public class GenType5 : GenClass<int> { } 

and this logic:

public class SomeClass {
    public void Add<T>(GenClass<T> t) { }
}

and this consumer:

public class Consumer {
    public void Method() {
        var some = new SomeClass();
        some.Add(new GenType1());
        some.Add(new GenType2());
        some.Add(new GenType3());
        some.Add(new GenType4());
        some.Add(new GenType5());
    }
}

But instead of adding each GenType(n) separately, I create a method like this:

public void AddFromAssembly<TAssembly>(SomeClass some, Type baseType) {
    var list = typeof(TAssembly).Assembly.GetTypes()
        .Where(t => baseType.IsAssignableFrom(t)
            && !baseType.Equals(t))
        .ToList();
    list.ForEach(type => {
        var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null,
                                       Type.EmptyTypes, null);
        var obj = ctor.Invoke(new object[] { });
        some.Add(obj); //????
    });
}

and want to call it like this:

public class Consumer {
    public void Method() {
        var some = new SomeClass();
        AddFromAssembly<GenType1>(some, typeof(GenClass<>));
    }
}

But some.Add method is a generic method and ctor.Invoke method returns an object. Have you any idea to solve this problem? Thanks in advance.

UPDATE The question was incomplete, I fix it. Thanks for review.

回答1:

Either do this:

Add<object>(obj); //this will work with T typed as object

or:

typeof(Some).GetMethod("Add").MakeGenericMethod(new [] { typeof(obj.GetType()).Invoke(some, new [] { obj });

The reflection version will use the exact type of obj for T at runtime.



回答2:

Type parameters to generics are a compile time required and can't be determine at runtime (unless you want to get into the hassle of creating class definitions at runtime).

What you'll likely need to do is create a second version of the method that is typed for "object" and use that instead.