IEnumerable<T> and reflection
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.
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++;
}
}
}
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..
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?
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.
}
}
}
精彩评论