97

空合并大致转换为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);,但如果你有更好的方法,我也想看看。)

4

12 回答 12

66

Groovy 中有null-safe 取消引用运算符(?.) ...我认为这就是您所追求的。

(也称为安全导航算子。)

例如:

homePostcode = person?.homeAddress?.postcode

如果person, person.homeAddressorperson.homeAddress.postcode为空,这将给出空值。

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

于 2010-05-28T14:25:51.300 回答
38

更新:请求的功能已添加到 C# 6.0。以下 2010 年的原始答案应仅被视为具有历史意义。


我们考虑添加?。到 C# 4。它没有成功;这是一个“很高兴拥有”的功能,而不是“必须拥有”的功能。我们将再次考虑该语言的假设未来版本,但如果我是你,我不会屏住呼吸等待。随着时间的推移,它不太可能变得更加重要。:-)

于 2010-05-29T04:19:26.670 回答
17

如果您有一种特殊的短路布尔逻辑,您可以这样做(javascript 示例):

return x && x.y;

如果x为 null,则不会计算x.y.

于 2010-05-28T14:33:44.583 回答
7

将其添加为答案感觉是对的。

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

然而,我并不是说我不想看到它!

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

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

于 2010-05-28T14:36:01.123 回答
6

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

他们正在考虑添加一个?运算符到 C# 4.0 来做同样的事情,但这得到了砧板。

与此同时,有 IfNotNull()有点抓痒。它肯定大于?。或 :,但它确实允许您组成一系列操作,如果其中一个成员为空,则不会对您造成 NullReferenceException。

于 2010-05-28T14:33:28.473 回答
3

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

  • Nothing >> NothingNothing
  • Nothing >> Just 1Nothing
  • Just 2 >> NothingNothing
  • Just 2 >> Just 1Just 1
于 2010-05-28T14:50:25.700 回答
3

Haskell 有fmap,在这种情况下我认为它相当于Data.Maybe.map. Haskell 纯粹是功能性的,所以你正在寻找的是

fmap select_y x

如果xNothing,则返回Nothing。如果xJust object,则返回Just (select_y object)。不像点符号那么漂亮,但鉴于它是一种函数式语言,样式是不同的。

于 2010-05-28T15:23:24.793 回答
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);
于 2010-05-28T14:41:17.397 回答
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"
于 2013-03-12T23:23:53.807 回答
1

使用成员的所有正确默认值在某处创建类的静态实例。

例如:

z = new Thingy { y=null };

然后代替你的

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

你可以写

return (x ?? z).y;
于 2012-01-04T19:20:09.870 回答
1

这是在 C# vNext 中添加的(Roslyn 支持的 C#,随 Visual Studio 2014 发布)。

它称为 Null 传播,并在此处列出为完整的。 https://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status

它也在这里完整列出: https ://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c

于 2014-11-30T22:11:53.613 回答
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/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators

于 2018-04-06T10:12:54.627 回答