【问题标题】:How to cast PropertyInfo value to ICollection<T> where T might be any class如何将 PropertyInfo 值转换为 ICollection<T>,其中 T 可能是任何类
【发布时间】:2016-02-21 18:47:24
【问题描述】:

我正在为断开连接的情况下的实体框架更新构建自己的通用解决方案。可以采用许多不同的方法,但我决定使用自定义属性装饰我的实体内部的 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 实例。在第 3 行中,当迭代器到达 Executors 属性时,第 5 行中的条件解析为 true。现在我需要遍历 Executors 属性并执行适当的任务。对于这种特殊情况,在第 6 行我可以说:

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

但是我如何确定在 ICollection&lt;T&gt; 中输入什么而不是 T 呢?

【问题讨论】:

  • 我已经重新格式化了你的一些代码,并为你的类命名。检查它们是否正常

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


【解决方案1】:

通常的解决办法是:

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

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

请注意,由于历史原因,IEnumerable&lt;T&gt; 基于IEnumerableICollection&lt;T&gt; 基于IEnumerable&lt;T&gt;,依此类推IEnumerable,但ICollection&lt;T&gt;不是基于在ICollection

一般来说,如果你想要IEnumerable&lt;T&gt; 的类型T,你可以(取自https://stackoverflow.com/a/906513/613130):

// 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&lt;T&gt; 而是仅基于 IEnumerable 的集合将返回 typeof(object)。基于多个IEnumerable&lt;T&gt; 的集合将只返回一个...例如:

public class MyStupidClass : IEnumerable<int>, IEnumerable<long>
{
}

但这是一个退化的例子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2016-03-25
    • 1970-01-01
    • 2014-02-05
    相关资源
    最近更新 更多