Reputation: 11334
I have the following class definition:
[ActionsClass[typeof(MyActions)]
public class NkProject
{
int ProjectId;
IList<NkItem> Items;
NkItem SingleItem;
}
The class mostly contains only fields, with the class attribute stating which class is responsible for "handling" this class as part of a larger framework.
Using reflection, I parse this file to generate some meta data and I'd like to know if "Items" is of type List (or any type of collection which acts as a list) but everything I've tried so far fails. I'm iterating over an array of FieldInfo[]
objects.
Check for IEnumerable
:
if(field.FieldType.GetInterface("IEnumerable") != null)
This also detects strings as IEnumerables, which is incorrect. I'd prefer if strings fail to pass this check and get treated as primitives in a sense (the else
of the above if
).
Changed above to: if(field is ICollection)
and that also fails.
Changed above to: if(field is IList && field.GetType().IsGenericType)
and it still fails to be detected correctly.
Is there a way to look only at the type of the variable references to ascertain whether Items
is of type List and a parallel check for string Items
fails? I'm guessing #2 and #3 above fail because Items
is not an object and thus there isn't any inheritance information attached to it. I could be wrong, but I think that's what is happening. A field.GetType().Name
returns the type as IList`1. Not sure how to get around this.
EDIT/UPDATE: If the above check fails, and a string goes through, the output meta is incorrectly formatted. Since, if it's a collection/list of items, I need to fetch further metadata for them (via the appropriately set attributes). This step is only executed if the variable is of type List/Collection but not if it's a single reference or a primitive.
Reflection code:
foreach (var field in fieldInfo)
{
Property property;
//If it's a collection field, get the appropriate collection name as set in its attribute
if (field.FieldType.GetInterface("IEnumerable") != null) //currently lets strings pass through too.
{
//Get the type of the "type argument" of the IEnumerable
Type[] typeArgs = field.FieldType.GetGenericArguments();
//Get the collection name for that type to use in the XML
MyAttribute att = (MyAttribute )Attribute.GetCustomAttribute(typeArgs[0], typeof(MyAttribute ));
if (att == null)
throw new ArgumentException("Using collection: {0} in Your class: {1}. Collection must have MyAttribute[Collection=\"\"] attribute defined on its class declaration.");
else
{
//do something with meta data
}
}
//If non-collection, possibly primitive field do something else
else
{
//do other stuff here.
}
}
Upvotes: 1
Views: 269
Reputation: 6577
You can try this method:
public bool IsGenericList(Type type)
{
if (type == null)
return false;
if (!type.IsGenericType)
return false;
var genericArguments = type.GetGenericArguments();
if (genericArguments.Length != 1)
return false;
var listType = typeof(IList<>).MakeGenericType(genericArguments);
return listType.IsAssignableFrom(type);
}
Upvotes: 1
Reputation: 1144
You can use the generic type information to check whether it is a List
if(field.FieldType.IsGenericType
&& field.FieldType.GetGenericTypeDefinition() == typeof(List<>))
currently I have the following function in my code base for this type of situation.
public static bool Closes(this Type type, Type openType)
{
if (type == null)
return false;
if (type.IsGenericType && type.GetGenericTypeDefinition() == openType) return true;
foreach (var @interface in type.GetInterfaces())
{
if (@interface.Closes(openType)) return true;
}
return type.BaseType.Closes(openType);
}
this would allow you to just call
field.FieldType.Closes(typeof(List<>)
Upvotes: 3