C#中的安全导航操作员?

Kyl*_*yle 7 c#

可能重复:
"如果object为null,则返回null;如果object不为null,则返回object.member"

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

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
Run Code Online (Sandbox Code Playgroud)

如何在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
Run Code Online (Sandbox Code Playgroud)

但是,这仅适用于某些情况.

flq*_*flq 10

对于这种情况,我倾向于使用一种名为的扩展方法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);
}
Run Code Online (Sandbox Code Playgroud)

更复杂的是介绍一个Maybe的概念.一个例子被带到由德里克·贝利在这里.

更新:

C#6开始,现在有一个零传播运算符,它的语法方式与Groovy运算符完全相同.


sta*_*ica 5

您正在寻找C# 语言版本 6(在 Visual Studio 2015 中推出)中引入的短路null 条件成员访问运算符。?.

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


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

其他一些选项:

首先,反建议——不要这样做:

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

其次,使用诸如Maybemonad 之类的东西——你可以自己定义这样的类型。它基本上是一个Nullable<T>实现IEnumerable<T>,当没有设置值时,它返回一个空序列,或者如果设置了一个值,则返回一个仅包含一个元素的序列。然后您可以按如下方式使用它:

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

第三,可能是最简单、最实用的解决方案,如 ulrichb 建议的:

var lname = person.Name != null ? person.Name.ToLower() : null;
Run Code Online (Sandbox Code Playgroud)

PS,因为我们已经讨论了检查 for 的主题null,所以不要忘记在访问其属性之前检查是否person是...;-)nullName