此代码引发异常
System.InvalidOperationException:找不到实体类型“列表<..>”。确保已将实体类型添加到模型中。
private static void Update<T>(DbContext context, ICollection<T> existing, ICollection<T> updated) // where T: class
{
context.RemoveRange(existing);
updated.ToList().ForEach(existing.Add);
}
但是,如果添加类型约束where T: class
,则不会引发异常。为什么是这样?我给人的印象是C#类型约束不影响这样的运行时行为。两种版本都可以正常编译。
答案 0 :(得分:6)
这不是运行时行为,而是此处的编译时方法重载解析和协方差:
context.RemoveRange(existing);
RemoveRange
方法有两个重载:
RemoveRange(IEnumerable<object> entities)
和
RemoveRange(params object[] entities)
具有类约束,C#编译器可以选择IEnumerable<object>
来重载-因为ICollection<T>
是IEnumerable<T>
,而引用类型IEnumerable<T>
的{{1}}是协变的,因此是T
。
没有类约束,唯一可用的选项是带有IEnumerable<object>
参数的方法。这是params object[]
构造的缺点/副作用/陷阱之一-类型为params object[]
的每个单个参数arg
被视为object[]
并隐式传递为{ {1}}。
所以,在前一种情况下,实际的呼叫是
object
在后一种情况下是
new object[] { arg }
换句话说,列表作为对象传递,这导致了相关的运行时异常。
context.RemoveRange((IEnumerable<object>)existing);
类的所有其他context.RemoveRange(new object[] { existing });
方法-Range
,DbContext
和AddRange
也是如此。