我有点难以理解这里的问题所在。我有一些代码使用 LINQ 从数据库中提取记录并将它们放入一个对象中,该对象被转换为一个接口(interface)。它看起来有点像这样:
public IEnumerable<ISomeObject> query()
{
return from a in dc.SomeTable
select new SomeObject
{
//Assign various members here
} as ISomeObject;
}
当我对此进行测试时,我将返回的 IEnumerable 放入一个名为 results 的变量中并运行以下行:
Assert.AreEqual(EXPECTED_COUNT, results.Count());
当它运行时,我得到一个 System.Security.VerificationException:“Operation could destabilize the runtime.”
我找到了解决方案 here , 这是这样的:
var results = from a in dc.SomeTable
select new SomeObject
{
//Assign various members here
} as ISomeTable;
return results.OfType<ISomeObject>();
这行得通,但我无法理解这里发生的事情。为什么我一开始会得到异常,上面的代码行是如何修复它的? MSDN 文档似乎暗示这是一个类型安全问题,但我没有看到以前的代码在哪里类型不安全。
更新 我发现了更多信息。如果我将返回类型设置为 IQueryable,则第一个示例有效。这更清楚地说明了什么出了问题,但我仍然对原因感到困惑。为什么编译器不强制我将 IEnumerable 转换为 IQueryable?
最佳答案
我认为这是 this forum post 指出的协变或逆变问题.
参见 Covariance and Contravariance in C#, Part Two: Array Covariance和其余的Covariance and Contravariance series在 Eric Lippert 的博客上。
虽然他在我链接的文章中处理数组,但我相信这里也会出现类似的问题。对于您的第一个示例,您将返回一个 IEnumerable
,它可能包含实现一个大于 ISomeTable
的接口(interface)的对象(即 - 您可以将当 IEnumerable 只能包含长颈鹿时,将 Turtle 转换为 Animals IEnumerable)。我认为当你返回 IQueryable
时它起作用的原因是因为它比你可以返回的任何东西都更大/更宽,所以你保证你返回的东西你将能够处理(?)。
在第二个例子中,OfType确保返回的是一个对象,该对象存储仅返回那些可以转换为 Giraffe 的元素所需的所有信息。
我很确定它与上面概述的类型安全问题有关,但正如 Eric Lippert 所说 Higher Order Functions Hurt My Brain我无法准确表达为什么这是一个协变/逆变问题。
关于c# - 操作可能会破坏运行时的稳定性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/378895/