如何将PropertyInfo值转换为ICollection <t>,其中T可以是任何类

时间:2016-02-19 13:58:24

标签: reflection generic-collections generic-type-argument

我正在为断开连接的场景中的Entity Framework更新构建自己的通用解决方案。可以采用许多不同的方法,但我决定使用自定义属性在我的实体内装饰ICollection属性,以便我可以检查这些集合中每个实体的状态。这是一个带有导航属性的示例实体:

public class SomeEntity 
{
    public int TaskId{ get; set; }
    public string Instruction { get; set; }
    [EntityNavigationProperty]
    public virtual ICollection<TaskExecutor> Executors { get; set; }
}

public class TaskExecutor 
{
    public int TaskExecutorId { get; set; }
    public int TaskId { get; set; }
    public virtual Task Task { get; set; }
}

public class EntityNavigationProperty : Attribute {}

我有一个通用的Update方法,我打算用它来更新任何类型的实体,以确保相关实体也能正确更新。

public void Update(TEntity entity)
{
    PropertyInfo[] properties = entity.GetType().GetProperties();
    foreach (PropertyInfo pi in properties)
    {
        if (Attribute.IsDefined(pi, typeof(EntityNavigationProperty)))
        {
            foreach (//here I need to iterate through the ICollection object)
            {

            }
        }
    }
}

现在,假设我正在向上述更新方法发送一个Task的instnce。在第3行中,当迭代器到达Executors属性时,第5行中的条件解析为true。现在我需要遍历Executors属性并执行适当的任务。对于这个特殊情况,在第6行我可以说:

  foreach (var item in (pi.GetValue(entity) as ICollection<TaskExecutor>))

但是如何确定在ICollection<T>中输入的内容而不是T?

1 个答案:

答案 0 :(得分:1)

通常的解决方案是:

foreach (object item in (IEnumerable)pi.GetValue(entity)) 
{
}

然后在里面检查item的类型。

请注意,由于历史原因,IEnumerable<T>基于IEnumerable,而ICollection<T>基于IEnumerable<T>,基于IEnumerable,但ICollection<T> } 不是基于ICollection

一般情况下,如果您想要T的{​​{1}}类型,可以(取自https://stackoverflow.com/a/906513/613130):

IEnumerable<T>

请注意,根据我已经介绍的更改,我创建了一些小副作用:不是基于// returns typeof(T) of an IEnumerable<T>, // or typeof(object) of an IEnumerable. public static Type GetGenericTOfIEnumerable(object o) { return o.GetType() .GetInterfaces() .Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)) .Select(t => t.GetGenericArguments()[0]) .FirstOrDefault() ?? (o is IEnumerable ? typeof(object) : null); } 的集合,但仅在IEnumerable<T>上会返回{{1} }。基于多个IEnumerable的集合将只返回一个...例如:

typeof(object)

但这是一个堕落的例子。