简体   繁体   中英

Enumerate ICollection<T> property of class using Reflection

I'm trying to create a base class for my POCO objects in .NET 4, which will have an Include(string path) method, where path is a "." delimited navigation path of nested ICollection properties of the inheriting class to be enumerated.

For example, given the following classes;

public class Region
{
    public string Name { get; set; }
    public ICollection<Country> Countries { get; set; }
}
public partial class Region : EntityBase<Region> {}

public class Country
{
    public string Name { get; set; }
    public ICollection<City> Cities { get; set; }
}
public partial class Country : EntityBase<Country> {}

public class City
{
    public string Name { get; set; }
}
public partial class City : EntityBase<City> {}

I want to be able to do something like this;

Region region = DAL.GetRegion(4);
region.Include("Countries.Cities");

So far I have the following;

public class EntityBase<T> where T : class 
{
    public void Include(string path)
    {
        // various validation has been omitted for brevity
        string[] paths = path.Split('.');
        int pathLength = paths.Length;
        PropertyInfo propertyInfo = type(T).GetProperty(paths[0]);
        object propertyValue = propertyInfo.GetValue(this, null);
        if (propertyValue != null)
        {
            Type interfaceType = propertyInfo.PropertyType;
            Type entityType = interfaceType.GetGenericArguments()[0];

            // I want to do something like....
            var propertyCollection = (ICollection<entityType>)propertyValue;
            foreach(object item in propertyCollection)
           {
               if (pathLength > 1)
               {
                   // call Include method of item for nested path
               }
           }
        }
    }
}

Clearly, the "var list = ...>" line doesn't work but you hopefully get the gist, and the foreach will not work unless is the propertyCollection is enumerable.

So it's the last bit, ie how do I enumerate an ICollection property of a class when I do not know the type of T until runtime?

Thanks

You don't need Reflection for this. In order to enumerate it, you only need an IEnumerable . ICollection<T> inherits IEnumerable , so all of your collections will be enumerables. Therefore,

var propertyCollection = (IEnumerable) propertyValue;
foreach (object item in propertyCollection)
    // ...

will work.

Generics are normally used when the client can resolve the generic type at compile -time. Leaving that aside, since all you need to do is enumerate the propertyCollection (viewing each element of the sequence simply as a System.Object ) all you need to do is:

var propertyCollection = (IEnumerable)propertyValue;
foreach(object item in propertyCollection)
{
    ...
}    

This is perfectly safe since ICollection<T> extends IEnumerable<T> , which in turn extends IEnumerable . What T actually ends up being at run-time is irrelevant since the loop only requires object .

The real question is: Is System.Object sufficient for your purposes inside the loop?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM