我正在为断开连接的场景中的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?
答案 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)
但这是一个堕落的例子。