views:

205

answers:

4

Background

Working in .NET 2.0 Here, reflecting lists in general. I was originally using t.IsAssignableFrom(typeof(IEnumerable)) to detect if a Property I was traversing supported the IEnumerable Interface. (And thus I could cast the object to it safely)

However this code was not evaluating to True when the object is a BindingList<T>.

Next

I tried to use t.IsSubclassOf(typeof(IEnumerable)) and didn't have any luck either.

Code

    /// <summary>
    /// Reflects an enumerable (not a list, bad name should be fixed later maybe?)
    /// </summary>
    /// <param name="o">The Object the property resides on.</param>
    /// <param name="p">The Property We're reflecting on</param>
    /// <param name="rla">The Attribute tagged to this property</param>
    public void ReflectList(object o, PropertyInfo p, ReflectedListAttribute rla)
    {
        Type t = p.PropertyType;
        //if (t.IsAssignableFrom(typeof(IEnumerable)))
        if (t.IsSubclassOf(typeof(IEnumerable)))
        {
            IEnumerable e = p.GetValue(o, null) as IEnumerable;

            int count = 0;
            if (e != null)
            {
                foreach (object lo in e)
                {
                    if (count >= rla.MaxRows)
                        break;

                    ReflectObject(lo, count);

                    count++;
                }
            }
        }
    }

The Intent

I want to basically tag lists i want to reflect through with the ReflectedListAttribute and call this function on the properties that has it. (Already Working)

Once inside this function, given the object the property resides on, and the PropertyInfo related, get the value of the property, cast it to an IEnumerable (assuming it's possible) and then iterate through each child and call ReflectObject(...) on the child with the count variable.

+6  A: 

When you do the as IEnumerable and the variable is not null you know that it does implement IEnumerable interface.

You don´t need the code:

Type t = p.PropertyType;
//if (t.IsAssignableFrom(typeof(IEnumerable)))
if (t.IsSubclassOf(typeof(IEnumerable)))
{

This would be enough:

public void ReflectList(object o, PropertyInfo p, ReflectedListAttribute rla)
{
    IEnumerable e = p.GetValue(o, null) as IEnumerable;

    int count = 0;
    if (e != null)
    {
        foreach (object lo in e)
        {
            if (count >= rla.MaxRows)
                break;
            ReflectObject(lo, count);
            count++;
        }
    }
}
Jens Granlund
Wow this is what happens when you return to old code when you discover you mocked it up long ago and it doesn't work. Now that you mention it, I haven't the foggiest idea how i missed that >_<. Thanks
Aren
+2  A: 

Why do you the if-statement at all?

You already did a var e = ... as IEnumerable and afterwards just check if is not null.

Isn't that enough?

Oliver
+1  A: 

These work. :)

A List is extended Collection. So, the tests are different for them. A Dictionary has got two internal containers. Hence one test for the same.

public static bool IsList(object obj)
{
    System.Collections.IList list = obj as System.Collections.IList;
    return list != null;
}

public static bool IsCollection(object obj)
{
    System.Collections.ICollection coll = obj as System.Collections.ICollection;
    return coll != null;
}

public static bool IsDictionary(object obj)
{
    System.Collections.IDictionary dictionary = obj as System.Collections.IDictionary;
    return dictionary != null;
}



Usage example -

if (IsDictionary(fieldObject)) //key-value type collection?
{
    System.Collections.IDictionary dictionary = fieldObject as System.Collections.IDictionary;
    foreach (object _ob in dictionary.Values)
    {
        //do work
    }
    // dictionary.Clear();
}
else //normal collection
{
    if (IsCollection(fieldObject))
    {
        System.Collections.ICollection coll = fieldObject as System.Collections.ICollection;
        foreach (object _ob in coll)
        {
            //do work
        }

        if (IsList(fieldObject))
        {
            //System.Collections.IList list = fieldObject as System.Collections.IList;
            //list.Clear(); // <--- List's function, not Collection's.
        }
    }
}
Nayan
I wouldn't recommend using that pattern, as it does redundant casts. It is expected to do a null check after using "as", this results in simpler code (no extra method call needed) and a single cast (see Jens answer).
J c
I understand. These are functions I posted, for re-usability purpose. Jens method does simplify these by in-lining the code, but also provides space for duplicates. OP gets to choose, now.
Nayan
+1  A: 

From MSDN

The IsSubclassOf method cannot be used to determine whether an interface derives from another interface, or whether a class implements an interface Use the GetInterface method for that purpose

Also your implementation of IsAssignableFrom is wrong, you should use it like this:

typeof(IEnumerable).IsAssignableFrom(t)

This should return true if IEnumerable is implemented by t..

Islam Ibrahim