受约束的执行区域(CER)是创作可靠托管代码的机制的一部分。 CER 定义了一个区域,其中公共语言运行时(CLR)被限制以避免抛出带外的异常,这些异常将使该区域内的代码无法完全执行。 在该区域中,用户代码被限制,无法执行可能引发带外异常的代码。 该PrepareConstrainedRegions方法必须紧接在try
块之前,并将catch
、finally
和fault
块标记为受约束的执行区域。 标记为受约束区域后,代码只能调用具有强可靠性协定的其他代码,并且代码不应分配或对未准备或不可靠的方法进行虚拟调用,除非代码准备处理故障。 CLR 会延迟对在 CER 中执行代码的线程中止操作。
重要
CER 仅在 .NET Framework 中受支持。 本文不适用于 .NET Core 或 .NET 5 及更高版本。
除带批注 try
块外,约束的执行区域还以 CLR 中的不同形式使用,尤其是在派生自 CriticalFinalizerObject 类的类中执行的关键终结器以及使用 ExecuteCodeWithGuaranteedCleanup 该方法执行的代码。
CER 事先准备
CLR 事先准备 CER 以避免出现内存不足的情况。 需要预先准备,因此 CLR 不会在实时编译或类型加载期间导致内存不足的情况。
开发人员需要指示代码区域是 CER:
事先已准备好顶级 CER 区域和完整调用关系图中应用了 ReliabilityContractAttribute 属性的方法。 ReliabilityContractAttribute只能声明保证Success或MayFail。
对于无法静态确定的调用,例如虚拟调度,无法进行提前准备。 请在这些情况下使用 PrepareMethod 方法。 使用ExecuteCodeWithGuaranteedCleanup方法时,PrePrepareMethodAttribute属性应应用于清理代码。
约束
用户可以在 CER 中编写的代码类型中受到约束。 该代码不会导致带外的异常,例如,可能由以下操作导致:
显式分配。
拳击。
获取锁。
虚拟调用未准备好的方法。
调用弱可靠性协定或不存在可靠性协定的方法。
在 .NET Framework 版本 2.0 中,这些约束是准则。 诊断通过代码分析工具提供。
可靠性协定
ReliabilityContractAttribute这是一个自定义属性,用于记录给定方法的可靠性保证和损坏状态。
可靠性保证
可靠性保证(由 Cer 枚举值表示)指示给定方法的可靠性程度:
MayFail。 在特殊情况下,该方法可能会失败。 在这种情况下,该方法会向调用者报告其成功或失败的情况。 该方法必须包含在 CER 中,以确保它可以报告返回值。
None。 方法、类型和程序集没有 CER 的概念,如果状态损坏没有得到实质性的缓解,在 CER 内进行调用很可能是不安全的。 它不利用 CER 保证。 这意味着:
在特殊情况下,该方法可能会失败。
方法可能报告失败,也可能不报告失败。
该方法并不是为了使用 CER 而编写的,这种情况是最有可能发生的。
如果方法、类型和程序集没有显示标识为成功,则会隐式标识为 None。
Success。 在特殊情况下,该方法可以保证成功。 为了实现这种可靠性级别,应始终围绕调用的方法构造 CER,即使从非 CER 区域中调用它也是如此。 方法是否成功取决于它是否完成了预期目标,尽管成功的定义可以是主观的。 例如,标记 Count 为
ReliabilityContractAttribute(Cer.Success)
意味着在 CER 下运行时,它始终返回 ArrayList 中元素数量的计数,并且永远不会使内部字段处于不确定的状态。 但是,CompareExchange 方法也标记为成功,此处的成功意味着该值不会因争用条件而替换为新值。 关键点是,该方法的行为方式与文档中描述的相符,并且不需要编写 CER 代码来处理任何超出正确但不可靠代码表现的异常行为。
腐败程度
损坏级别由 Consistency 枚举值表示,指示给定坏境中状态的损坏程度:
MayCorruptAppDomain。 在特殊情况下,公共语言运行时(CLR)无法保证当前应用程序域中的状态一致性。
MayCorruptInstance。 在特殊情况下,此方法保证将状态损坏限制在当前实例。
MayCorruptProcess,在特殊情况下,CLR 不保证状态一致性:也就是说,条件可能会损坏进程。
WillNotCorruptState。 在异常情况下,此方法保证不会损坏状态。
可靠性 try/catch/finally
可靠性 try/catch/finally
是一种异常处理机制,其可预测性保证级别与非托管版本相同。
catch/finally
块为 CER。 块中的方法需要预先准备,并且必须不可中断。
在 .NET Framework 2.0 版中,代码通过在 try 块之前直接调用 PrepareConstrainedRegions 来通知运行时 try 是可靠的。 PrepareConstrainedRegions 是编译器支持类的成员 RuntimeHelpers。 在其通过编译器变得可用之前,直接调用 PrepareConstrainedRegions。
不可中断的区域
不可中断的区域将一组指令分组到 CER 中。
在 .NET Framework 2.0 版中,通过使用编译器支持暂停可用性,用户代码创建不可中断的区域,其中具有包含前面是 PrepareConstrainedRegions 方法调用的空 try/catch 块的可靠 try/catch/finally。
关键终结器对象
CriticalFinalizerObject 保证垃圾回收会执行终结器。 进行分配时,应事先准备好终结器及其调用关系图。 终结器方法在 CER 中执行,并且必须遵从所有关于 CER 和终结器的约束。
任何继承自SafeHandle和CriticalHandle的类型都保证其终结器在 CER 中执行。 在 ReleaseHandle 派生的类中实现 SafeHandle 以执行释放图柄所需的任何代码。
CER 中不允许的代码
CER 中不允许以下操作:
显示分配。
获取锁。
拳击。
多维数组访问。
通过反射进行的方法调用。
安全检查。 不执行请求,仅链接请求。
获取或设置透明代理上的字段。
序列化。
函数函数指针和委托。