简体   繁体   中英

How to find the concrete type of interface instance when using reflection?

I'm currently trying to create an instance of an object that was defined as an interface. Specifically:

public static class A {
    public static IList<string> SampleList { get; set; }

    public void Initialize() { 
        SampleList = new List<string>();
    }
}

// In some other class where I don't have an instance of A.
// This class is in a separate DLL + running in a separate process as A
var propertyInfo = typeof(A).GetProperty("SampleList");
propertyInfo.PropertyType.GetConstructors().Any(); // false
// ^ I would like this to be true

When SampleList is instead typed as a List instead of the interface (IList) I'm able to produce a constructor and instantiate an instance of this list. I have the same luck with Arrays + other instances that aren't defined as an interface.

Something else I noticed is that when I use List, and invoke PropertyType.GetInterfaces() I get a list of 8 interfaces while when I invoke the same command using an IList instance I only get 3 interfaces. In general I'm getting a lot less information.

I was wondering if it was possible to find out the concrete class itself? If so, how?

Use GetType() to get the type of the concrete instance.

    var propertyInfo = typeof(A).GetProperty("SampleList");
    var propertysTypeHasConstructor = propertyInfo.PropertyType.GetConstructors().Any(); // false
    Console.WriteLine(propertysTypeHasConstructor);

    var concreteInstanceType = A.SampleList.GetType();
    var concreteInstanceHasConstructor = concreteInstanceType.GetConstructors().Any(); // true
    Console.WriteLine(concreteInstanceHasConstructor);

Output:

False
True

John Wu's answer should work if you already have an instance of an object on which you can call GetType. If you just have a type like IList<string> , or any interface type, you won't find a constructor. I think the closest you could get would be to search the assemblies in the AppDomain for a type that implements the interface and has a default constructor.

var interfaceType = typeof(IList<string>);
var ctor = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(a =>
    {
        try
        {
            return a.GetTypes();
        }
        catch
        {
            return new Type[0];
        }
    })
    .Select(t => interfaceType.IsGenericType && t.IsGenericType && interfaceType.GetGenericArguments().Length == t.GetGenericArguments().Length && t.GetGenericArguments().All(a => a.GetGenericParameterConstraints().Length == 0) ? t.MakeGenericType(interfaceType.GetGenericArguments()) : t)
    .Where(interfaceType.IsAssignableFrom)
    .SelectMany(t => t.GetConstructors())
    .FirstOrDefault(c => c.GetParameters().Length == 0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM