空合并运算符是否有“对立”?(...用任何语言?)


92

空合并大致可转换为 return x, unless it is null, in which case return y

我经常需要 return null if x is null, otherwise return x.y

我可以用 return x == null ? null : x.y;

不错,但是null中间总是困扰着我-似乎是多余的。我更喜欢这样的东西return x :: x.y;::只有在它之前的东西不在时,它后面的才被评估null

我认为这是几乎与简洁,内联零检查的对面空聚结,那种复杂的,但我[ ]一定会出现在C#中没有这样的运营商。

是否还有其他具有这种运算符的语言?如果是这样,它叫什么?

(我知道我可以在C#中为它编写一个方法;我使用return NullOrValue.of(x, () => x.y);,但是如果您有更好的东西,我也想看看。)


有些人在C#中要求类似x?.y的东西,但是不存在这样的东西。
安东尼·佩格拉姆

1
@安东尼哦,那太好了。谢谢。
杰伊(Jay)

2
在c ++中,将其轻松表达为即可return x ? x.y : NULL。是的,用于将指针类型转换为布尔值!
Phil Miller'5

1
@Novelocrat在C#中最让我烦恼的事情之一是,如果if(anything)= true,除非它们是if(0,false,null),否则他们没有跟随C
Chris Marisic 2010年

2
@Chris:关于C的说法不正确。如果您有非标量变量(例如struct),则不能在条件中使用它。
·米勒

Answers:


62

Groovy中有一个空安全解引用运算符(?。)...我想这就是您要追求的。

(也称为安全导航操作员。)

例如:

homePostcode = person?.homeAddress?.postcode

如果或为null person,则将为null。person.homeAddressperson.homeAddress.postcode

(现在在C#6.0中可用,但在早期版本中不可用)


1
Groovy还具有“猫王运算符”,它允许使用除之外的其他默认值null,例如:def bar = foo ?: "<null>"
Craig Stuntz 2010年

28
我为C#5.0提名了此功能。我不知道或不在乎Groovy到底是什么,但这很直观,可以在任何语言中使用。
捷尔吉Andrasek

但是,现在将其添加到C#6中,万岁。
Jeff Mercado 2015年

1
安全导航适用于微不足道的示例,但如果要在函数调用中使用非null值,则仍需要使用三元运算符,例如:Decimal? post = pre == null ? null : SomeMethod( pre );。如果可以将其缩减为“ Decimal?post = pre :: SomeMethod(pre);”,那将是很好的。

@戴:鉴于您可能想要的排列数量,我对我们所拥有的感到很满意。
乔恩·斯基特

36

我们考虑添加?。到C#4。这是一个“不错的”功能,而不是“一定要”的功能。我们将在假设的将来版本中再次考虑该语言,但是如果您是我,我不会屏息等待。随着时间的流逝,它不可能变得越来越重要。:-)


是否易于实施功能会影响添加功能的决定?我之所以这么问,是因为实现该运算符似乎很简单,是对语言的简单补充。我不是专家(只是最近对C#热爱的应届毕业生),所以请纠正我!
尼克·斯特鲁帕

14
@nick:当然,实现词法分析器和解析器需要五分钟的时间。然后,您开始担心诸如“ IntelliSense引擎处理得好吗?”之类的问题。以及“当您键入?而不是。时,错误恢复系统如何处理呢?” 以及“做”多少不同的事情。无论如何在C#中意味着什么,其中有多少值得拥有?在此之前,以及如果您弄错了错误消息应该是什么,以及此功能需要进行多少测试(提示:很多)。我们将如何记录它并传达更改,以及...
埃里克·利珀特

3
@nick:要回答您的问题-是的,实现成本是一个因素,但是很小。在我们工作的级别上,没有便宜的功能,只有或多或少的昂贵功能。花费五美元的开发人员的工作才能使解析器在正确的代码情况下工作,很容易变成数万美元的设计,实现,测试,文档和培训。
埃里克·利珀特

11
@EricLippert我认为这将是主要的“不错的东西”之一,它使C#如此成功,并且也将完美地实现使代码尽可能简洁明了的使命!
康斯坦丁

我想看到这个加,我真正想要的是埃尔维斯操作:stackoverflow.com/questions/2929836/...
克里斯Marisic

16

如果您有一种特殊的短路布尔逻辑,则可以执行此操作(javascript示例):

return x && x.y;

如果x为null,则不会求值x.y


2
除此之外,还会在0,“”和NaN上短路,因此与??相反。与||相反。
ritaj

7

将此添加为答案只是感觉正确。

我想为什么C#中没有这样的原因是因为,与合并运算符(仅对引用类型有效)不同,反向操作可以生成引用或值类型(即class x具有成员)int y,因此不幸的是在许多情况下无法使用。

但是,我并不是说我不想看到它!

对于该问题的一种潜在解决方案是,操作员可以自动将右侧的值类型表达式提升为可为空的值。但是,您会遇到x.y一个问题,其中y是一个int实际上会返回an int?,这会很痛苦。

另一个可能更好的解决方案是,如果左侧的表达式为null,则运算符将为右侧的类型返回默认值(即null或零)。但是,您可能会遇到区分实际读取零/空x.y或是否由安全访问操作员提供的情况的问题。


当我第一次阅读OP的问题时,这个确切的问题突然浮现在脑海中,但是我无法确定如何表达它。这是一个非常严重的问题。+1
rmeador

这不是一个严重的问题。只需将其int?用作默认返回值,用户便可以根据需要将其更改为int。例如,如果我想调用某个Lookup默认值为-1的方法,以防我的引用之一是nullfoo?.Bar?.Lookup(baz) ?? -1
Qwertie 2012年

如何?. :成为一个三元运算符,要求右侧与中间给出的适当成员具有相同的类型?
2013年

6

Delphi具有:(而不是。)运算符,该运算符是null安全的。

他们正在考虑添加?。操作员对C#4.0进行相同的操作,但是得到了斩波块。

在此期间,IfIfNull()会产生痒感。它肯定比?大。或:,但确实可以让您组成一系列操作,如果其中一个成员为null,则不会向您发出NullReferenceException异常。


你能举一个使用这个运算符的例子吗?
Max Carroll 2015年

1
?.是C#6.0语言的功能,是的,它完全符合OP在这里所要求的。迟到总比不到好^^
T_D

3

在Haskell中,您可以使用>>运算符:

  • Nothing >> NothingNothing
  • Nothing >> Just 1Nothing
  • Just 2 >> NothingNothing
  • Just 2 >> Just 1Just 1

3

Haskell有fmap,在这种情况下,我认为这相当于Data.Maybe.map。Haskell纯粹是功能性的,因此您想要的是

fmap select_y x

如果xNothing,则返回Nothing。如果xJust object,则返回Just (select_y object)。不像点符号那样漂亮,但是考虑到它是一种功能语言,因此样式是不同的。


2

PowerShell让您在null引用上引用属性(但不能调用方法),如果实例为null,它将返回null。您可以在任何深度进行。我曾希望C#4的动态功能能够支持这一点,但事实并非如此。

$x = $null
$result = $x.y  # $result is null

$x = New-Object PSObject
$x | Add-Member NoteProperty y 'test'
$result = $x.y  # $result is 'test'

它不是很漂亮,但是您可以添加一个扩展方法,该方法将按照您描述的方式起作用。

public static TResult SafeGet<T, TResult>(this T obj, Func<T, TResult> selector) {
    if (obj == null) { return default(TResult); }
    else { return selector(obj); }
}

var myClass = new MyClass();
var result = myClass.SafeGet(x=>x.SomeProp);

2
public class ok<T> {
    T s;
    public static implicit operator ok<T>(T s) { return new ok<T> { s = s }; }
    public static implicit operator T(ok<T> _) { return _.s; }

    public static bool operator true(ok<T> _) { return _.s != null; }
    public static bool operator false(ok<T> _) { return _.s == null; }
    public static ok<T> operator &(ok<T> x, ok<T> y) { return y; }
}

我经常需要对字符串使用以下逻辑:

using ok = ok<string>;

...

string bob = null;
string joe = "joe";

string name = (ok)bob && bob.ToUpper();   // name == null, no error thrown
string boss = (ok)joe && joe.ToUpper();   // boss == "JOE"

1

在所有位置使用所有正确的默认值的地方创建类的静态实例。

例如:

z = new Thingy { y=null };

然后代替你的

return x != null ? x.y : null;

你可以写

return (x ?? z).y;

我有时会使用该技术(例如(x ??“”).ToString()),但它仅适用于一些数据类型,例如POD和字符串。
Qwertie 2012年


1

在C#6.0和Visual Basic 14中引入了所谓的“空条件运算符”。
在许多情况下,它可以用作与空值运算符完全相反的功能:

int? length = customers?.Length; // null if customers is null   
Customer first = customers?[0];  // null if customers is null  
int? count = customers?[0]?.Orders?.Count();  // null if customers, the first customer, or Orders is null

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/null-conditional-operators

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.