什么是'无法验证的代码',为什么它不好?

Geo*_*uer 20 c#

我正在设计一个帮助方法,为我延迟加载某些对象,调用它看起来像这样:

public override EDC2_ORM.Customer Customer {
    get { return LazyLoader.Get<EDC2_ORM.Customer>(
            CustomerId, _customerDao, ()=>base.Customer, (x)=>Customer = x); }
    set { base.Customer = value; }
}
Run Code Online (Sandbox Code Playgroud)

当我编译此代码时,我收到以下警告:

警告5通过匿名方法,lambda表达式,查询表达式或迭代器中的'base'关键字访问成员'EDC2_ORM.Billing.Contract.Site'会导致无法验证的代码.考虑将访问权限移动到包含类型的辅助方法中.

这里的投诉到底是什么,为什么我做得不好?

Jar*_*Par 25

虚拟方法的"base.Foo"将对方法"Foo"的父定义进行非虚拟调用.从CLR 2.0开始,CLR决定对虚拟方法进行非虚拟调用可能是一个潜在的安全漏洞,并限制了可以使用的场景.他们将其限制为在同一类层次结构中对虚拟方法进行非虚拟调用.

Lambda表达式在这个过程中发生了变化.Lambda表达式通常会在引擎盖下生成一个闭包,这是一个完全独立的类.因此代码"base.Foo"最终将成为一个全新类中的表达式.这会在CLR中创建验证异常.因此C#发出警告.

附注:等效代码适用于VB.在VB中,对虚拟方法进行非虚拟调用,将在原始类中生成方法存根.非虚拟呼叫将在此方法中执行."base.Foo"将被重定向到"StubBaseFoo"(生成的名称不同).


Jon*_*eet 9

我怀疑问题在于你基本上是在说,"我不想使用客户最常用的实现 - 我想使用这个特定的实现" - 你通常无法做到这一点.您可以在派生类中执行此操作,并且有充分的理由,但是从其他类型开始,您将违反封装.

现在,当您使用匿名方法,lambda表达式,查询表达式(基本上使用lambda表达式)或迭代器块时,编译器有时必须在幕后为您创建一个新类.有时它可以为lambda表达式创建一个相同类型的新方法,但它取决于上下文.基本上,如果在lambda表达式中捕获任何局部变量,那么需要一个新类(或者实际上是多个类,这取决于范围 - 它可能会变得令人讨厌).如果lambda表达式仅捕获this引用,则可以为lambda表达式逻辑创建新的实例方法.如果没有捕获任何内容,静态方法就可以了.

因此,虽然C#编译器知道你真的没有违反封装,但CLR却没有 - 所以它会怀疑地对待代码.如果您在完全信任下运行,那可能不是问题,但在其他信任级别(我不知道详细信息),您的代码将不被允许运行.

这有帮助吗?