我在理解这里的问题时遇到了一些麻烦.我有一些代码使用LINQ从数据库中提取记录,并将它们放入一个被转换为接口的对象中.看起来有点像这样:
public IEnumerablequery() { 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:"操作可能会破坏运行时的稳定性."
我在这里找到了解决方案,这是:
var results = from a in dc.SomeTable select new SomeObject { //Assign various members here } as ISomeTable; return results.OfType();
这有效,但我无法理解这里发生的事情.为什么我首先得到异常,上面的代码行是如何解决的?MSDN文档似乎表明这是类型安全的问题,但我没有看到以前的代码类型不安全的地方.
更新 我发现的更多信息.如果我返回类型IQueryable,第一个示例有效.这揭示了一点点光什么是走错了,但我仍然感到困惑的原因.为什么编译器不强迫我将IEnumerable转换为IQueryable?
我认为这是一个协方差或逆转问题,如本论坛帖所述.
请参阅 Eric Lippert博客中的C#中的协方差和逆变,第二部分:数组协方差以及协方差和逆变系列的其余部分.
虽然他在我链接的文章中处理数组,但我相信类似的问题在这里出现.有了您的第一个例子,你是返回一个IEnumerable
可能包含实现一个接口,对象较大的比ISomeTable
(即-你可以把龟到动物的IEnumerable时IEnumerable的只能包含长颈鹿).我认为当你返回时它起作用的原因IQueryable
是因为它比你可以返回的任何东西更大/更宽,所以你保证你返回的东西能够处理(?).
在第二个示例中,OfType确保返回的内容是一个对象,该对象存储了仅返回可以强制转换为Giraffe的元素所需的所有信息.
我很确定它与上面列出的类型安全问题有关,但正如Eric Lippert所说,高阶函数伤害了我的大脑,而我很难准确地说出为什么这是一个共同/逆变问题.
我在寻找自己的解决方案时找到了这个条目,"操作可能会破坏运行时的稳定性".虽然上面的协方差/反差方案建议看起来非常有趣,但最后我发现通过运行我的单元测试并启用代码覆盖率和AllowPartiallyTrustedCallers程序集属性集,我得到了相同的错误消息.
删除AllowPartiallyTrustedCallers属性导致我的测试运行正常. 我也可以关闭代码覆盖率以使它们运行但这不是一个可接受的解决方案.
希望这有助于其他人访问此页面,试图找到解决此问题的方法.
只是猜测,但是as运算符可能返回null - 因此它可能与new SomeObject { ... }
代码的实际实现有关,因为它是语法糖.在return results.OfType
基于类型的过滤器,让你的方法的return语句将只返回类型(确保类型安全).我遇到了返回泛型类型的类似问题.
PS我喜欢"操作会破坏运行时的稳定性".例外.这几乎就像"你可能会炸毁互联网"一样.