约束执行区域(CER)
受约束的执行区域 (CER) 是创作可靠托管代码的机制的一部分。CER 定义一个区域,在该区域中公共语言运行库 (CLR) 会受到约束,不能引发可使区域中的代码无法完全执行的带外异常。在该区域中,用户代码受到约束,不能执行会导致引发带外异常的代码。PrepareConstrainedRegions 方法必须直接位于 try块之前,并将 catch、finally 和 fault 块标记为受约束的执行区域。标记为受约束的区域后,代码只能调用其他具有强可靠性约定的代码,而且代码不应分配或者对未准备好的或不可靠的方法进行虚调用,除非代码已经准备好处理错误。CLR 为 CER 中正在执行的代码延迟线程中止。
除批注的 try 块外,受约束的执行区域还以其他形式用于 CLR 中,特别是在从 CriticalFinalizerObject 类派生的类中执行的关键终止程序和使用ExecuteCodeWithGuaranteedCleanup 方法执行的代码。
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 区域内进行调用。如果一个方法完成了其任务,它就是成功的,虽然这种成功可能只是主观认为的成功。例如,用 ReliabilityContractAttribute(Cer.Success) 标记 Count 意味着当它在 CER 下运行时,它始终返回 ArrayList 中元素的数目的计数,并且它永远不能将内部字段保留为不确定状态。 但是,CompareExchange方法也标记为成功,这里的成功意味着该值不会因争用条件而替换为新值。 关键在于该方法的行为方式与记录的行为方式相同,不需要在 CER 代码中处理除正确但不可靠代码的行为之外的任何非正常行为。
损坏级别
损坏级别由 Consistency 枚举值表示,指示给定环境下状态的损坏程度:
-
MayCorruptAppDomain 。在异常情况下,公共语言运行库 (CLR) 对当前应用程序域中的状态一致性不做任何保证。
-
MayCorruptInstance 。在异常情况下,该方法保证将状态损坏限制到当前实例。
-
MayCorruptProcess ,在异常情况下,CLR 对状态一致性不做任何保证;即这种情况可能会损坏进程。
-
WillNotCorruptState 。在异常情况下,保证该方法不会损坏状态。
可靠性 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 内执行其终结器。在 SafeHandle 派生类中实现 ReleaseHandle 可执行释放句柄所需的所有代码。
CER 中不允许下面的操作:
-
显式分配。
-
获取锁。
-
装箱。
-
多维数组访问。
-
通过反射进行的方法调用。
-
安全检查。不执行命令,仅链接命令。
-
获取或设置透明代理上的字段。
-
序列化。
函数指针和委托。
-
class Program
{
static void Main()
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Console.WriteLine("try");
}
finally
{
type.dosome();
}
Console.WriteLine();
Console.ReadKey();
}
}
class type
{
static type()
{
Console.WriteLine("ctor");
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static void dosome()
{
}
}
-