C# 参数是否有合并运算符?

C# 参数是否有合并运算符?,c#,C#,如果F在a上,我可以这样做 var obj = a?.F(); var obj = a == null ? null : MyFunc.F((A) a); 如果F不在a上,我必须这样做 var obj = a?.F(); var obj = a == null ? null : MyFunc.F((A) a); 还是我?如果参数值为null,是否有更简洁的方法跳过方法调用?简短的回答是否,没有简洁的方法可以做到这一点 稍长一点的答案仍然是否定的,但这里有一个有趣的语言设计要点。C是由非常

如果F在a上,我可以这样做

var obj = a?.F();
var obj = a == null ? null : MyFunc.F((A) a);
如果F不在a上,我必须这样做

var obj = a?.F();
var obj = a == null ? null : MyFunc.F((A) a);

还是我?如果参数值为null,是否有更简洁的方法跳过方法调用?

简短的回答是否,没有简洁的方法可以做到这一点

稍长一点的答案仍然是否定的,但这里有一个有趣的语言设计要点。C是由非常有品味的人设计的,如果我自己这么说的话,但它是经过很长一段时间设计的。这一点最明显的莫过于它对可空性的处理

在C 1中,我们在C、C++、java、JavaScript等传统中有一种直截了当的语言,在这里有引用和值,引用可以是空的。这有好处;如果不是这样,托尼爵士一开始就不会发明空引用。但它也有缺点:我们有可能出现空引用,取消空引用会导致程序崩溃,并且引用类型和值类型之间存在不一致性:引用类型有一个自然的无值值值,而值类型没有

在C2.0中,我们添加了可空值类型,但可空值类型的行为与可空引用类型不同。当然,可为null的值类型不是引用,因此您无法取消引用它们,但是如果我们稍微看一看,.Value属性看起来非常类似于取消引用,如果该值为null,则会导致类似的崩溃。从这个意义上讲,它们的行为是相同的,但在其他意义上,它们却不同。如果两个可为null的整数中有一个为null,那么将它们相加不会崩溃;相反,结果也是空的

因此,在这一点上,语言中有一个矛盾:

使用可空值类型的空值通常会自动传播空值,但使用空引用可能会崩溃

当然,C接着添加了各种特性,使空引用的行为更像空值,比如?。以及相关的操作。还有一些关于C8的建议非常令人兴奋,它们将支持不可为null的引用类型场景

但上面的粗体文本是您指出的基本问题:可空引用类型上的运算符的语义几乎总是将运算符的不可空版本提升到可空类型;如果所有操作数均为非空,则结果与未升级版本相同;否则,结果为空。但是,这些语义不会自动扩展到。成员访问运算符或调用运算符,无论操作数是可空值类型还是可空引用类型。可通过?明确提升?。但是操作符永远不会被提升到可空语义

设想一种类似于C1.0的语言,但从一开始就内置了Nullable,这样它就可以应用于引用类型和值类型。在这个世界上,你可以看到实现广义提升的自然方法,如果你有一个方法

class C { string M(double, int[]) }
使用可空接收器或可空和可空参数调用它,您会自动获得我们为您构建的用于可空整数算术的代码:检查接收器或任何参数是否为空,如果为空,则会导致可空。否则,请正常调用该函数并使用不可为空的结果

C编译器已经为所有在结构类型上声明的用户定义运算符实现了这些语义;将这些语义扩展到其他类型的方法几乎没有任何困难。但我们现在不能这样做;有太多的向后兼容性问题需要解决

这种设计选择还具有一个很好的特性,即它是maybe monad的正确实现


但这不是我们所处的世界,这主要是因为这些设计考虑因素随着时间的推移而演变,而不是一下子被发明出来的。下一次你发明一种新的语言时,仔细考虑如何表示可空性! 只要合并这些值。如果a是某物{MyFunc.Fsomething;}简洁而不清晰是许多错误的开始。@Davesoft我不想要a,我想要MyFunc.Fa。你能不能把空保护放在F里面?我希望在调用函数之前进行显式空检查。您可以将null检查放在函数中-如果a为null,则返回null-但是最终结果可能是null值这一点不太明显。如果有可能以空值结束,我希望这是显而易见的。