Determine with reflection if a class property is a

2019-08-26 14:11发布

问题:

I am needing to use reflection to filter out all object properties that are collections. Now, they are not just Generic list always, but a class that inherits a List type. So as an example, I have class foo(). A property of class foo() is the class fooCollection(). FooColection looks like the following:

    public class foo
    {
         public FooCollection myCollection {get;set;}
    }


    public class fooCollection : List<Foo>
    {



    }

I do not know what to expect as the type of List, but only need to know if it is a collection. How can I find this out? I asked a prior question, but worded it differently, and the results were not working with my particular instance.

I have tried exampels such as the following where i look through all properties of foo, and try to find the property that is fooColelction:

typeof(IEnumerable<>).IsAssignableFrom(prop.PropertyType)

This is not working properly for me though. The type is not IEnumerable, though it is a collection. It inherits an IEnumerable type. Thanks in advance.

Here is an example of one of the Collection classes for a class object called Policy.

public class PolicyCollection : List<Policy>
{
    /// <summary>
    /// This function takes a xml Policy collection and builds a PolicyCollection Class
    /// </summary>
    /// <param name="xDocPolicyCollection">XML Document of an PolicyCollection</param>
    protected internal void LoadXml(XmlDocument xDocPolicyCollection)
    {
        foreach (XmlNode n in xDocPolicyCollection.GetElementsByTagName("Policy"))
        {
            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(n.OuterXml);

            Policy p = new Policy();
            p.LoadXml(xdoc);
            Add(p);
        }
    }

    /// <summary>
    /// This function takes a datatable of Policies collection and builds a PolicyCollection Class
    /// </summary>
    /// <param name="dtContact">Data</param>
    protected internal void LoadDB(DataTable dtPolicyCollection)
    {
        foreach (DataRow dr in dtPolicyCollection.Rows)
        {
            Policy p = new Policy();
            p.LoadDB(dr);
            Add(p);
        }
    }
}

This is different then a prior question because I am asking how to check this scenario for a property type that is a regular class, that Inherits List, not a property that is List.

回答1:

The main problem is that a non-reified generic type (such as IEnumerable<>) can never be assigned anything. .NET generics simply don't work this way.

Instead, you could use something like this:

typeof(PolicyCollection)
.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))

GetInterfaces returns all the interfaces which are implemented by the given type, and then you simply check if there's anything that's an IEnumerable<>. By explicitly un-reifying the found generic interfaces, we can do a simple comparison with IEnumerable<> (or IList<> or whichever you prefer).

And of course, since IEnumerable<> also "requires" IEnumerable, you can simply check for that instead of the generic interface:

typeof(IEnumerable).IsAssignableFrom(typeof(PolicyCollection));