C# 是否保证外部选中/未选中上下文会影响在其内部创建的lambda的行为?

C# 是否保证外部选中/未选中上下文会影响在其内部创建的lambda的行为?,c#,lambda,language-lawyer,unchecked-conversion,C#,Lambda,Language Lawyer,Unchecked Conversion,假设算术溢出(非)检查,下面的代码 Action<Int32[]> action; checked { action = array => Console.WriteLine(array[0] + array[1]); } var items = new[] { Int32.MaxValue, Int32.MaxValue }; action(items); 动作; 选中的 { 动作=数组=> Console.WriteLine(数

假设算术溢出(非)检查,下面的代码

Action<Int32[]> action;

checked
{
    action = array =>
        Console.WriteLine(array[0] + array[1]);
}

var items = new[]
{
    Int32.MaxValue,
    Int32.MaxValue
};
action(items);
动作;
选中的
{
动作=数组=>
Console.WriteLine(数组[0]+数组[1]);
}
var项目=新[]
{
Int32.MaxValue,
Int32.MaxValue
};
行动(项目);
将导致

System.OverflowException:算术运算导致溢出

如果我们将项目设置设置为,并将
checked{
替换为
unchecked{
,则不会引发异常


那么,我们可以依赖这种行为吗?还是更安全地取消选中数组(数组[0]+数组[1])?

在上一次正式发布的C#spec中,它说:

8.11(…)checked语句使块中的所有表达式在选中的上下文中求值,而unchecked语句使块中的所有表达式在未选中的上下文中求值。(…)

我可以非常自信地说,
操作
将始终在检查/未检查的上下文中进行评估,这是您当前看到的行为,我预计这在将来不会改变


为了进一步扩展我的答案,如果您检查编译后的代码,您将看到
Console.WriteLine(数组[0]+array[1])
中的
checked
语句实际上编译为与
Console.WriteLine(checked(数组[0]+array[1])等效的语句
因此确实没有必要自己做,编译器无论如何都会做。

请记住,
已选中
未选中
更改编译器发出的指令。例如,有两条指令(实际上更多)IL中
add
指令的变体,其中一个变体忽略溢出,另一个变体检查溢出

因为它改变了发射的IL,所以必须应用它


例如,该代码:

    static void Main(string[] args)
    {
        int i = 0;
        int j = 1;
        int k;
        checked
        {
            k = i + j;
        }
        unchecked
        {
            k = i + j;
        }
        Console.ReadLine();
    }
发出此IL:

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 num,
        [1] int32 num2,
        [2] int32 num3)
    L_0000: nop 
    L_0001: ldc.i4.0 
    L_0002: stloc.0 
    L_0003: ldc.i4.1 
    L_0004: stloc.1 
    L_0005: nop 
    L_0006: ldloc.0 
    L_0007: ldloc.1 

    L_0008: add.ovf 

    L_0009: stloc.2 
    L_000a: nop 
    L_000b: nop 
    L_000c: ldloc.0 
    L_000d: ldloc.1 

    L_000e: add 

    L_000f: stloc.2 
    L_0010: nop 
    L_0011: call string [mscorlib]System.Console::ReadLine()
    L_0016: pop 
    L_0017: ret 
}

您可以在其中看到发出的两条不同指令。

最好将C#视为具有两组整数运算符,其中一组执行溢出检查,另一组不执行;无论“+”运算符绑定到“溢出检查加法”运算符还是“换行加法”加法运算符由它是否出现在选中或未选中的上下文中来控制。运算符影响程序执行的唯一方式是选择哪些运算符绑定到“+”之类的标记;这种绑定发生在编译器检查代码时,而不是在运行代码时。

是的,我知道检查/取消检查是如何工作的。我只想知道它是否保证以与(un)中为lambdas生成的方法相同的方式影响选中的上下文。@EugenePodskal-那么我误解了这种混淆。如果有人认为
checked
就像
try
/
catch
一样隐藏了溢出异常,我可以理解这种混淆;也就是说,它是在运行时实现的,因此lambda中的代码没有在sam中执行很重要e时间范围为
选中的
块。你想要保证C#编译器没有任何错误??github网站列出了一万个问题,其中三分之一仍然存在。我刚才查看时碰巧遇到:)@HansPassant据我所知,这里没有错误-一切都很好,逻辑性很强。But我担心的是,人们是否可以将这种行为作为一种标准。中提到的规范有点模糊,并且lambdas是否保证会受到影响仍然有点怀疑。当它不起作用,并且你有一个具体的问题要向我们展示时,请回来,因为它总是存在的。@HansPassant我并不完全同意这种追求ion离题了。这只是一个语言律师问题,而不是一个具体的“我的代码不起作用”问题。好吧,我们似乎可以从字面上理解
8.11
,所以在检查lambda的身体时,它应该会受到影响。谢谢,尽管我可能会继续应用
(联合国)在lambda内部选中
-它应该是可靠的,并且更本地化/更短。