Kit*_*Kit 21 c# c#-6.0 null-conditional-operator
我有这些扩展方法和枚举类型:
public static bool IsOneOf<T>(this T thing, params T[] things)
{
return things.Contains(thing);
}
public static bool IsOneOf<T>(this T? thing, params T[] things) where T : struct
{
return thing.HasValue && things.Contains(thing.Value);
}
public enum Color { Red, Green, Blue }
Run Code Online (Sandbox Code Playgroud)
if下面的第一个编译; 第二个不是:
if ((x.Y?.Color).IsOneOf(Color.Red, Color.Green))
;
if (x.Y?.Color.IsOneOf(Color.Red, Color.Green))
;
Run Code Online (Sandbox Code Playgroud)
它们仅因额外的括号而异.为什么我要这样做?
起初我怀疑它是从做一个双隐式转换bool?到bool,然后回bool?,但是当我删除第一个扩展方法,它抱怨不存在隐式转换,从bool到bool?.然后我检查了IL并且没有演员阵容.反编译回C#会产生如下情况:
if (!(y != null ? new Color?(y.Color) : new Color?()).IsOneOf<Color>(new Color[2]
{
Color.Red,
Color.Green
}));
Run Code Online (Sandbox Code Playgroud)
这对于我正在运行的CLR版本以及我的期望是好的.我没想到的是x.Y?.Color.IsOneOf(Color.Red, Color.Green)不编译.
到底是怎么回事?它只是语言实现的方式,它需要()吗?
更新
这是一个显示上下文错误的屏幕截图.这让我更加困惑.错误实际上是有道理的; 但是什么(我现在不在意)是为什么第18行不会有同样的问题.
首先,这种行为对我来说是有意的.很少有人为可空类型添加扩展方法,人们在一个表达式中混合使用空条件和常规成员访问是很常见的,因此语言有利于后者.
请考虑以下示例:
class B { bool c; }
class A { B b; }
...
A a;
var output = a?.b.c; // infers bool?, throws NPE if (a != null && a.b == null)
// roughly translates to
// var output = (a == null) ? null : a.b.c;
Run Code Online (Sandbox Code Playgroud)
而
A a;
var output = (a?.b).c; // infers bool, throws NPE if (a == null || a.b == null)
// roughly translates to
// var output = ((a == null) ? null : a.b).c;
Run Code Online (Sandbox Code Playgroud)
然后有
A a;
var output = a?.b?.c; // infers bool?, *cannot* throw NPE
// roughly translates to
// var output = (a == null) ? null : (a.b == null) ? null : a.b.c;
// and this is almost the same as
// var output = (a?.b)?.c; // infers bool?, cannot throw NPE
// Only that the second `?.` is forced to evaluate every time.
Run Code Online (Sandbox Code Playgroud)
这里的设计目标似乎是帮助区分a?.b.c和a?.b?.c.如果a为null,我们希望在任何情况下都不会获得NPE .为什么?因为之后有一个空条件a.因此,.c只有a在不为null的情况下才能评估该部分,使得成员访问依赖于先前的null-conditionals结果.通过添加显式括号,(a?.b).c我们强制编译器尝试访问.c而(a?.b)不管是否为anull,从而阻止它将整个表达式"短路"为null.(使用@JamesBuck -s单词)
在你的情况下,x.Y?.Color.IsOneOf(Color.Red, Color.Green)就像a?.b.c.它将使用签名调用函数bool IsOneOf(Color red)(因此param不可为空的重载,并且我剥离了泛型部分)仅当x.Y非空时,因此将表达式的类型包装在Nullable中以处理x.Ynull 时的情况.并且因为while计算bool?而不是bool,它不能在if语句中用作测试.
| 归档时间: |
|
| 查看次数: |
524 次 |
| 最近记录: |