views:

178

answers:

3

I have a function with this code:

foreach (PropertyInfo propertyInfo in typeof(T).GetProperties()){
//SOME CODE
if (propertyInfo.CanWrite)
    propertyInfo.SetValue(myCopy, propertyInfo.GetValue(obj, null), null);
}

I would avoid to check "collection" properties; to do this now I have insert this control:

 if (propertyInfo.PropertyType.Name.Contains("List")
     || propertyInfo.PropertyType.Name.Contains("Enumerable")
     || propertyInfo.PropertyType.Name.Contains("Collection"))
     continue;

but, It don't like me!

Which is a better way to do it?

+4  A: 

I would probably check against IEnumerable.

if ((typeof(string) != propertyInfo.PropertyType) 
    && typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType))
{
    continue;
}
LukeH
Oh oh, now I have a problem...this condition is true also for string property. Is possible?
LukePet
I solve with the other posted solution.
LukePet
@LukePet: Strings implement `IEnumerable` because they're collections of characters. Anthony's answer specifically excludes strings, so you're right to choose that one (and I've updated my answer to follow suit).
LukeH
Are there other primitive types that implement IEnumerable like 'string'?
LukePet
@LukePet: None that I'm aware of.
LukeH
+2  A: 

bool isCollection = typeof(System.Collections.IEnumerable).IsAssignableFrom(propertyInfo.PropertyType);

MaLio
+4  A: 

I was thinking you might want to check the interfaces the type of the property implements. (Removed redundant interfaces, as IList inherits ICollection and ICollection inherits IEnumerable.)

static void DoSomething<T>()
{
    List<Type> collections = new List<Type>() { typeof(IEnumerable<>), typeof(IEnumerable) };

    foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
    {
        if (propertyInfo.PropertyType != typeof(string) && propertyInfo.PropertyType.GetInterfaces().Any(i => collections.Any(c => i == c)))
        {
            continue;
        }

        Console.WriteLine(propertyInfo.Name);
    }
}

I added code to not reject string, as it implements IEnumerable, as well, and I figured you might want to keep those around.

In light of the redundancy of the prior list of collection interfaces, it may be simpler just to write the code like this

static void DoSomething<T>()
{
    foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
    {
        if (propertyInfo.PropertyType != typeof(string)
            && propertyInfo.PropertyType.GetInterface(typeof(IEnumerable).Name) != null
            && propertyInfo.PropertyType.GetInterface(typeof(IEnumerable<>).Name) != null)
        {
            continue;
        }

        Console.WriteLine(propertyInfo.Name);
    }
}
Anthony Pegram
+1 Removed my answer as this is better.
GenericTypeTea
IEnumerable<> implements IEnumerable, there is no need to check for IEnumerable<>
MaLio