除非应用了,否则任何人都可以创建一个中断的短样本[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
吗?
我刚刚在 MSDN 上浏览了这个示例,即使我注释掉了 ReliabilityContract 属性,也无法让它崩溃。最后似乎总是被调用。
除非应用了,否则任何人都可以创建一个中断的短样本[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
吗?
我刚刚在 MSDN 上浏览了这个示例,即使我注释掉了 ReliabilityContract 属性,也无法让它崩溃。最后似乎总是被调用。
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
class Program {
static bool cerWorked;
static void Main( string[] args ) {
try {
cerWorked = true;
MyFn();
}
catch( OutOfMemoryException ) {
Console.WriteLine( cerWorked );
}
Console.ReadLine();
}
unsafe struct Big {
public fixed byte Bytes[int.MaxValue];
}
//results depends on the existance of this attribute
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
unsafe static void StackOverflow() {
Big big;
big.Bytes[ int.MaxValue - 1 ] = 1;
}
static void MyFn() {
RuntimeHelpers.PrepareConstrainedRegions();
try {
cerWorked = false;
}
finally {
StackOverflow();
}
}
}
当MyFn
被 jitted 时,它会尝试ConstrainedRegion
从finally
块中创建一个。
在ReliabilityContract,
没有正确的情况下ConstrainedRegion
可以形成,因此发出常规代码。调用时会抛出堆栈溢出异常Stackoverflow
(在执行 try 块之后)。
在 的情况下ReliabilityContract
,ConstrainedRegion
可以形成 a 并且可以将finally
块中方法的堆栈要求提升到MyFn
. 堆栈溢出异常现在在调用时抛出MyFn
(在执行 try 块之前)。
此功能的主要驱动力是支持 SQL Server 将 CLR 集成到 SQL Server 2005 的严格要求。可能是为了让其他人可以使用并且可能出于法律原因,这种深度集成作为托管 API 发布,但技术要求是 SQL Server。请记住,在 SQL Server 中,MTBF 以月而不是小时为单位来衡量,并且由于发生未处理的异常而重新启动进程是完全不可接受的。
这篇MSDN 杂志文章可能是我见过的描述受约束的执行环境所针对的技术要求的最佳文章。
ReliabilityContract 用于装饰您的方法,以指示它们如何根据潜在的异步异常(ThreadAbortException、OutOfMemoryException、StackOverflowException)进行操作。受约束的执行区域被定义为 try 块的 catch 或 finally(或错误)部分,紧接在调用 System.Runtime.CompilerServices.RuntimeServices.PrepareConstrainedRegions() 之前。
System.Runtime.CompilerServices.RuntimeServices.PrepareConstrainedRegions();
try
{
// this is not constrained
}
catch (Exception e)
{
// this IS a CER
}
finally
{
// this IS ALSO a CER
}
在 CER 中使用 ReliabilityContract 方法时,会发生两件事。该方法将由 JIT 预先准备好,这样它就不会在第一次执行时调用 JIT 编译器,这可能会尝试使用内存本身并导致它自己的异常。此外,在 CER 内部时,运行时承诺不会抛出 ThreadAbort 异常,并且会等到 CER 完成后才抛出异常。
回到你的问题;我仍在尝试提出一个简单的代码示例来直接回答您的问题。正如您可能已经猜到的那样,考虑到问题的异步性质,最简单的示例将需要相当多的代码,并且很可能是 SQLCLR 代码,因为这是使用 CER 获得最大收益的环境。
您是否在调试器下运行 MSDN 示例?我认为当您在调试器中执行时,CER 不可能起作用,因为调试器本身无论如何都会改变执行的性质。
如果您在优化发布模式下构建和运行应用程序,您应该能够看到它失败。
虽然我没有具体的例子给你,但我认为你错过了在保证成功的方法中尝试 try..finally 的要点。说方法总是成功的意思是,在执行过程中发生什么(异常),将采取措施确保方法返回时正在访问的数据处于有效状态。如果没有 try..finally,您将无法确保任何事情,并且可能意味着您想要发生的操作只有一半会发生。因此,Cer.Success 实际上并不能保证成功,它只是表明您作为开发人员正在保证成功。
查看此页面,了解 Success 和 MayFail 状态之间的差异,因为它与 Array.CopyTo 方法有关:http ://weblogs.asp.net/justin_rogers/archive/2004/10/05/238275.aspx
CER 属性是记录的手段。它们确实会影响 CLR 在某些情况下执行代码的方式,但我相信它们(或缺少它们)永远不会在当前版本的 .NET 中导致错误。
它们大多是“保留以备将来使用”。