受约束的执行区域

受约束的执行区域 (CER) 是创建可靠托管代码机制的一部分。 CER 定义一个区域,该区域内公共语言运行时 (CLR) 会受到约束,不能引发阻止该区域内代码完全执行的带外异常。 在该区域中,用户代码受到约束,不能执行会导致引发带外异常的代码。 PrepareConstrainedRegions 方法应该立即先于 try 块执行并将 catchfinallyfault 块标记为受约束的执行区域。 标记为受约束的区域后,代码只能调用其他具有强可靠性协定的代码,并且代码不应对未准备好或不可靠的方法进行分配和虚拟调用,除非该代码已准备好处理失败。 CLR 会为 CER 中正在执行的代码延迟线程中止。

重要

仅在 .NET Framework 中支持 CER。 本文不适用于 .NET Core 或 .NET 5 及更高版本。

除已批注的 try 块外,受约束的执行区域还以其他形式用于 CLR 中,特别是在 CriticalFinalizerObject 类派生的类中执行关键终结器和使用 ExecuteCodeWithGuaranteedCleanup 方法执行的代码。

CER 事先准备

CLR 事先准备 CER 以避免出现内存不足的情况。 需事先准备,防止 CLR 在实时编译或类型加载时发生内存不足的情况。

开发者需要指定一个代码区域作为 CER:

约束

用户可写入 CER 的代码类型受限。 代码无法导致带外异常,可能是以下操作引起的:

  • 显式分配。

  • 装箱。

  • 获取锁。

  • 虚拟调用未准备好的方法。

  • 调用弱可靠性协定或不存在可靠性协定的方法。

在.NET Framework version 2.0 版中,这些约束称为准则。 通过代码分析工具提供诊断。

可靠性协定

ReliabilityContractAttribute 是记录给定方法的可靠性保证和损坏状态的自定义属性。

可靠性保证

可靠性保证由 Cer 枚举值表示,指示给定方法的可靠程度:

  • MayFail。 异常情况下,方法可能会失败。 在这种情况下,方法会向调用方法报告是成功还是失败。 方法必须包含在 CER 中,以确保它可以报告返回值。

  • None。 方法、类型和程序集没有 CER 的概念,如果状态损坏没有得到实质性的缓解,在 CER 内进行调用很可能是不安全的。 它不利用 CER 保证。 这意味着:

    1. 异常情况下,方法可能会失败。

    2. 方法可能报告失败,也可能不报告失败。

    3. 最可能的方案是,未将方法编写为使用 CER。

    4. 如果方法、类型和程序集没有显示标识为成功,则会隐式标识为 None

  • Success。 异常情况下,保证方法一定成功。 若要达到这种级别的可靠性,应始终在调用的方法周围构造 CER,即使方法是从非 CER 区域调用的。 如果方法完成了预期任务,它就是成功的,虽然这种成功可能只是主观意义上的成功。 例如,用 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 和终结器的约束。

SafeHandleCriticalHandle 继承的任何类型都保证在 CER 内执行其终结器。 在 SafeHandle 派生的类中实现 ReleaseHandle 以执行释放图柄所需的任何代码。

CER 中不允许的代码

CER 中不允许以下操作:

  • 显示分配。

  • 获取锁。

  • 装箱。

  • 多维数组访问。

  • 通过反射进行的方法调用。

  • EnterLock

  • 安全检查。 不执行请求,仅链接请求。

  • COM 对象和代理的 IsinstCastclass

  • 获取或设置透明代理上的字段。

  • 序列化。

  • 函数函数指针和委托。

请参阅