条件 ref 表达式Conditional ref expressions

有条件地将 ref 变量绑定到一个或另一个表达式的模式当前目前不能用 c # 表达。The pattern of binding a ref variable to one or another expression conditionally is not currently expressible in C#.

典型的解决方法是引入如下方法:The typical workaround is to introduce a method like:

ref T Choice(bool condition, ref T consequence, ref T alternative)
{
    if (condition)
    {
         return ref consequence;
    }
    else
    {
         return ref alternative;
    }
}

请注意,这不会完全替换三元,因为所有参数都必须在调用站点进行计算。Note that this is not an exact replacement of a ternary since all arguments must be evaluated at the call site.

以下操作不会按预期方式工作:The following will not work as expected:

       // will crash with NRE because 'arr[0]' will be executed unconditionally
      ref var r = ref Choice(arr != null, ref arr[0], ref otherArr[0]);

建议的语法如下所示:The proposed syntax would look like:

     <condition> ? ref <consequence> : ref <alternative>;

可以使用 ref 三元 正确 编写以上带有 "Choice" 的尝试,如下所示:The above attempt with "Choice" can be correctly written using ref ternary as:

     ref var r = ref (arr != null ? ref arr[0]: ref otherArr[0]);

与选择的不同之处在于,可通过 真正 的条件方式访问结果和替代表达式,因此,如果 arr == nullThe difference from Choice is that consequence and alternative expressions are accessed in a truly conditional manner, so we do not see a crash if arr == null

三元 ref 只是一种三元,其中,替代项和结果都是 refs。The ternary ref is just a ternary where both alternative and consequence are refs. 这自然会要求结果/备用操作数为左值。It will naturally require that consequence/alternative operands are LValues. 它还要求结果和替代类型的类型相互转换。It will also require that consequence and alternative have types that are identity convertible to each other.

表达式的类型的计算方式与常规三元的类型类似。The type of the expression will be computed similarly to the one for the regular ternary. 亦.I.E. 在这种情况下,如果 "结果" 和 "替代" 具有转换标识,但类型不同,则将应用现有的类型合并规则。in a case if consequence and alternative have identity convertible, but different types, the existing type-merging rules will apply.

将从条件操作数中放心地假定安全返回。Safe-to-return will be assumed conservatively from the conditional operands. 如果任何一个不安全,则返回全部内容不安全。If either is unsafe to return the whole thing is unsafe to return.

Ref 三元是左值,因此它可以通过引用传递/赋值/返回;Ref ternary is an LValue and as such it can be passed/assigned/returned by reference;

     // pass by reference
     foo(ref (arr != null ? ref arr[0]: ref otherArr[0]));

     // return by reference
     return ref (arr != null ? ref arr[0]: ref otherArr[0]);

作为 LValue,还可以分配给。Being an LValue, it can also be assigned to.

    // assign to
    (arr != null ? ref arr[0]: ref otherArr[0]) = 1;

Ref 三元可以在常规 (中使用,也可以在) 上下文中使用。Ref ternary can be used in a regular (not ref) context as well. 尽管这不是很常见,但你也可以直接使用常规三元。Although it would not be common since you could as well just use a regular ternary.

     int x = (arr != null ? ref arr[0]: ref otherArr[0]);

实现说明:Implementation notes:

实现的复杂性似乎是从中等到大的 bug 修复的大小。The complexity of the implementation would seem to be the size of a moderate-to-large bug fix. -I. 开销不大。- I.E not very expensive. 我认为我们需要对语法或分析进行任何更改。I do not think we need any changes to the syntax or parsing. 对于元数据或互操作不起作用。There is no effect on metadata or interop. 此功能完全基于表达式。The feature is completely expression based. 对调试/PDB 不起任何作用No effect on debugging/PDB either