【问题标题】:Safe Navigation Operator in C#? [duplicate]C# 中的安全导航运算符? [复制]
【发布时间】:2011-05-05 20:52:49
【问题描述】:

可能重复:
Shortcut for “null if object is null, or object.member if object is not null”

有些语言有一个安全的导航操作符,让您不必担心空引用异常。

语言示例Groovy:

String lname = person.Name.ToLowerCase(); //throws exception if Name is null
String lname = person.Name?.ToLowerCase();//lname will be null if Name was null

如何在 C# 中完成类似的操作?到目前为止,我的解决方案是这样的扩展方法:

public static T o<T>(this T obj) where T : new()
{
            return obj != null ? obj : new T();
}
//used like: String lname = person.o().Name; //returns null if person was null

但是,这只在某些情况下有效。

【问题讨论】:

标签: c#


【解决方案1】:

对于这种情况,我倾向于使用一种名为IfNotNull的扩展方法:

public static OUT IfNotNull<IN, OUT>(this IN v, Func<IN, OUT> f) 
  where IN : class where OUT : class
{
  return v == null ? null : f(v);
}

更复杂的是引入 Maybe 的概念。 derick bailey here 举了一个例子。

更新:

C# 6 开始,现在有一个空传播运算符,它在语法方面看起来与 Groovy 完全一样。

【讨论】:

  • 这似乎是一个不错的解决方案。允许您不破坏方法链接并且不必引入临时变量,这是我想使用安全导航运算符的主要原因。
  • 这取决于 OUT 是可空类型。您可以通过以下方式将其扩展到所有类型:1. 删除 where OUT : class,2. 将正文更改为 return v == null ? default(OUT) : f(v);
  • v 是如何从 o 派生而来的?这就是重点,如果 o 不为空,就可以用它做某事。
【解决方案2】:

您正在寻找 C# 语言版本 6(在 Visual Studio 2015 中推出)中引入的短路 null-conditional member access operator ?.

我的答案的其余部分是为没有 ?. 运算符的 C# 语言的早期版本编写的。


一般来说,如果您正在访问一个深度“嵌套”的属性,例如 outermostObject.a.b.c.X,您可能应该考虑重新设计您的代码,因为这样的访问可能表明您正在违反既定的面向对象原则(例如最少知识原则,又名得墨忒耳法则)。

其他一些选项:

首先,一个反暗示——不要这样做:

string lname = null;
try
{
    lname = Person.Name.ToLower();
}
catch (NullReferenceException ex) { }  // inefficient and ugly

第二,使用类似Maybe monad 的东西——你可以自己定义这样的类型。它基本上是一个Nullable&lt;T&gt;,它实现了IEnumerable&lt;T&gt;,这样它在没有设置值时返回一个空序列,或者如果设置了一个值,则返回一个只有一个元素的序列。然后您可以按如下方式使用它:

Maybe<string> personName = person.Name;
var lname = (from name in personName select name.ToLower()).FirstOrDefault();

第三个,可能是最简单和最实用的解决方案,正如 ulrichb 所建议的那样:

var lname = person.Name != null ? person.Name.ToLower() : null;

PS,由于我们已经讨论了检查null 的主题,请不要忘记在访问Name 属性之前检查person 是否为null。 . ;-)

【讨论】:

    【解决方案3】:

    我不知道从保证不为 null 的东西返回 null,但为了保证对象引用,您可以使用 Null Coalescing Operator ??

    类似:

    string lname = (person.Name??String.Empty).ToLower();
    

    对于 null 情况,它将返回一个空字符串而不是 null,但它会起作用。

    返回空字符串比返回 null 更有意义;如果你返回一个 null,如果你将另一个运算符链接到它上面,它会再次抛出。

    【讨论】:

    • 你可以写一个ToLowerCase 扩展方法,但我可能只是在字符串对象上使用内置的ToLower 方法。
    • +1 用于使用?? 运算符。
    • ??是我最喜欢的 C# 运算符。
    【解决方案4】:

    目前在 C# 中不存在,但您可以使用 SelectMany 编写它。

    String lname = from _ in person.Name from s in _.ToUpper() select s;
    

    String lname = person.Name.SelectMany(_ => _.ToUpper(), s => s);
    

    (这是 Bart De Smet 在 his PDC 2010 talk on the future of LINQ 中的提议。参见幻灯片 #6。)

    【讨论】:

    • 请注意,在这种情况下,SelectMany 不是通常的 LINQ SelectMany,而是为实现 Maybe monad 而创建的自定义 SelectMany
    猜你喜欢
    • 2017-12-22
    • 2017-05-27
    • 2012-03-13
    • 2016-04-07
    • 2016-04-08
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多