我正在设计一个帮助方法,为我执行某些对象的延迟加载,调用它看起来像这样:
public override EDC2_ORM.Customer Customer {
get { return LazyLoader.Get<EDC2_ORM.Customer>(
CustomerId, _customerDao, ()=>base.Customer, (x)=>Customer = x); }
set { base.Customer = value; }
}
当我编译此代码时,我收到以下警告:
警告5访问会员 'EDC2_ORM.Billing.Contract.Site' 来自一个'base'关键字 匿名方法,lambda表达式, 查询表达式或迭代器结果 在无法验证的代码中。考虑搬家 访问辅助方法的方法 包含类型。
这里的投诉到底是什么,为什么我做得不好?
答案 0 :(得分:23)
虚拟方法的“base.Foo”将对方法“Foo”的父定义进行非虚拟调用。从CLR 2.0开始,CLR决定对虚拟方法的非虚拟调用可能是潜在的安全漏洞,并限制了可以使用的场景。他们将其限制为对同一类层次结构中的虚拟方法进行非虚拟调用。
Lambda表达式在这个过程中发生了变化。 Lambda表达式通常会在引擎盖下生成一个闭包,这是一个完全独立的类。因此代码“base.Foo”最终将成为一个全新类中的表达式。这会在CLR中创建验证异常。因此C#发出警告。
备注:等效代码适用于VB。在VB中,对虚拟方法进行非虚拟调用,将在原始类中生成方法存根。非虚拟呼叫将在此方法中执行。 “base.Foo”将被重定向到“StubBaseFoo”(生成的名称不同)。
答案 1 :(得分:9)
我怀疑问题在于你基本上是在说,“我不想使用最派生的客户实现 - 我想使用这个特别的” - 你不会这样做能够正常做到。您可以在派生类中执行此操作,并且有充分的理由,但是从其他类型开始,您将违反封装。
现在,当您使用匿名方法,lambda表达式,查询表达式(基本上使用lambda表达式)或迭代器块时,编译器有时必须在幕后为您创建一个新类。有时它可以为lambda表达式创建一个相同类型的新方法,但它取决于上下文。基本上,如果在lambda表达式中捕获任何局部变量,那么需要一个新类(或者实际上是多个类,这取决于范围 - 它可能会变得令人讨厌)。如果lambda表达式仅捕获this
引用,则可以为lambda表达式逻辑创建新的实例方法。如果没有捕获任何内容,静态方法就可以了。
所以,虽然C#编译器知道你真的没有违反封装,但CLR却没有 - 所以它会怀疑地对待代码。如果您在完全信任下运行,那可能不是问题,但在其他信任级别(我不知道详细信息),您的代码将不被允许运行。
这有帮助吗?
答案 2 :(得分:2)
从here复制/粘贴:
Codesta:C#/ CLR有两种代码,安全且不安全。它试图提供什么以及它如何影响虚拟机? Peter Hallam:对于C#来说,这些术语是安全且不安全的。 CLR使用可验证且无法验证的术语。
当运行可验证的代码时,CLR可以强制执行安全策略; CLR可以防止可验证的代码执行它无权执行的操作。例如,当运行从互联网上下载的潜在恶意代码时,CLR将只运行可验证的代码,并确保不受信任的代码不会访问它无权访问的任何内容。
使用标准C样式指针会产生无法验证的代码。 CLR原生支持C风格指针。一旦获得了C样式指针,就可以读取或写入进程中的任何内存字节,因此运行时无法强制执行安全策略。实际上它可以,但性能损失将使其不切实际。
现在,这并没有完全回答你的问题(即为什么这是现在无法验证的代码),但至少它解释了“无法验证”是“不安全”的CLR术语。我假设匿名方法和基类在内部产生一些时髦的指针魔法。
按顺序:我认为代码段与警告消息不匹配。代码是在讨论客户,警告是关于账单的。是否可以发布生成警告的执行代码?也许你在代码中有其他东西可以更好地解释为什么你会收到警告。