0

I need to use reflection to filter out all object properties that are collections. They are not always just generic lists, but a class that inherits a List<T> type. So as an example, I have a class foo with property of type 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<T>, 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 examples 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.

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<T>, not a property that is List<T>.

CarenRose
  • 1,266
  • 1
  • 12
  • 24
Casey ScriptFu Pharr
  • 1,672
  • 1
  • 16
  • 36
  • Can you include the `FooCollection` class code? – Arghya C Oct 13 '15 at 12:06
  • Yes, one moment. I will put a general example to demonstrate. Now, instead of Foo, and fooCollection obviously this example is for Policy, and PolicyCollection. – Casey ScriptFu Pharr Oct 13 '15 at 12:06
  • @Yuval I don't thing `Type.IsGenericType` will work for OP's scenario where there's a type inheriting `List`. Anyway OP, please create a [mcve]. – CodeCaster Oct 13 '15 at 12:08
  • It is not duplicate, as the answer was not correct for my situation. If the property was public List then the question you are referencing would work, but it not. – Casey ScriptFu Pharr Oct 13 '15 at 12:09
  • 2
    Why do you need to know if the type is a list? This might be an XY problem. What is the actual problem you are trying to solve? – Luaan Oct 13 '15 at 12:11
  • 1
    @CodeCaster But checking agains't `IList` will work. I don't think OP needs the generic type parameter. – Yuval Itzchakov Oct 13 '15 at 12:12
  • To only check if those properties are not null and init for unit test. If I iterate all. I wanted to use reflection, so that it was reusable, generic. – Casey ScriptFu Pharr Oct 13 '15 at 12:12
  • 1
    Like @Luaan said, that screams XY problem. You shouldn't inherit from `List` in general, and you certainly should not have to resort to reflection in unit tests. – CodeCaster Oct 13 '15 at 12:13
  • Would I maybe need to check base type of the property, then the example? – Casey ScriptFu Pharr Oct 13 '15 at 12:30

1 Answers1

2

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));
Luaan
  • 62,244
  • 7
  • 97
  • 116
  • I tried this, and didn't work. See this is weird to me. Why it is not recognizing that the property is a collection. I am using var prop in object.GetProperties() to check the class foo. In that foreach, is where I am running your test against the prop. Instead of "typeof(PolicyCollction)" i am using "prop.GetType()" since it is unknown at that time what T is for List. – Casey ScriptFu Pharr Oct 13 '15 at 12:29
  • 1
    @Casey: You need to use the [`PropertyInfo.PropertyType` property](https://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo.propertytype%28v=vs.110%29.aspx), not `.GetType()`. `PropertyType` will get you the declared type of the property, whereas `GetType()` will get you the type of `prop` (which is `PropertyInfo`) – Chris Sinclair Oct 13 '15 at 12:32
  • No way, I am so sorry, and thank you so much. This helped me learn more about reflection going through this. That was the problem. Thanks again! – Casey ScriptFu Pharr Oct 13 '15 at 12:42