C#有多大用处? 运营商?

所以我被这个?所吸引。 运营商,但仍然无法使用它。 当我做的事情时,我通常会想到:

var x = (someObject as someType).someMember; 

如果someObject有效且someMember为null,我可以这样做

 var x = (someObject as someType).someMember ?? defaultValue; 

但是当someObject为null时,几乎总是遇到问题,而且?? 并没有帮助我使这个更干净,而不是自己做空检查。

你们找到了什么用途? 在实际情况?

我同意你的看法? 运算符通常用途有限 – 如果某些内容为空,则提供后备值非常有用,但如果您希望继续向下钻取有时属性或方法,则无法防止出现空引用exception。空引用。

恕我直言,还需要什么? 是一个“null-dereference”运算符,它允许您将长属性和/或方法链链接在一起,例如ab().cd().e而不必测试每个中间步骤的null-ness。 Groovy语言有一个安全导航操作符 ,非常方便。

幸运的是,似乎C#团队意识到了这个function差距。 请参阅此connect.microsoft.com建议 ,以便C#团队向C#语言添加null-dereference运算符。

我们收到了很多类似于此function的请求。 “?” 在社区讨论中提到的版本最接近我们的心 – 它允许你在每个“点”测试null,并与现有的很好地组合? 运营商:

a?.b?.c ?? d

意味着如果a,ab或abc中的任何一个为null,则使用d代替。

我们正在考虑将来发布这个版本,但它不会出现在C#4.0中。

再次感谢,

Mads Torgersen,C#语言PM

如果您还想在C#中使用此function,请将您的投票添加到连接网站上的建议中 ! 🙂

我用来解决缺少此function的一种解决方法是像本博文中所述的扩展方法,允许这样的代码:

 string s = h.MetaData .NullSafe(meta => meta.GetExtendedName()) .NullSafe(s => s.Trim().ToLower()) 

此代码返回h.MetaData.GetExtendedName().Trim().ToLower()或者如果h,h.MetaData或h.MetaData.GetExtendedName()为null,则返回null。 我还扩展了它以检查null或空字符串,或null或空集合。 这是我用来定义这些扩展方法的代码:

 public static class NullSafeExtensions { ///  /// Tests for null objects without re-computing values or assigning temporary variables. Similar to /// Groovy's "safe-dereference" operator .? which returns null if the object is null, and de-references /// if the object is not null. ///  /// resulting type of the expression /// type of object to check for null /// value to check for null /// delegate to compute if check is not null /// null if check is null, the delegate's results otherwise public static TResult NullSafe(this TCheck check, Func valueIfNotNull) where TResult : class where TCheck : class { return check == null ? null : valueIfNotNull(check); } ///  /// Tests for null/empty strings without re-computing values or assigning temporary variables ///  /// resulting type of the expression /// value to check for null /// delegate to compute non-null value /// null if check is null, the delegate's results otherwise public static TResult CheckNullOrEmpty(this string check, Func valueIfNotNullOrEmpty) where TResult : class { return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check); } ///  /// Tests for null/empty collections without re-computing values or assigning temporary variables ///  /// resulting type of the expression /// type of collection or array to check /// value to check for null /// delegate to compute non-null value /// null if check is null, the delegate's results otherwise public static TResult CheckNullOrEmpty(this TCheck check, Func valueIfNotNullOrEmpty) where TCheck : ICollection where TResult : class { return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check); } } 

?? operator类似于SQL中的coalesce方法,它为您提供第一个非null值。

 var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue; 

我通常将它用于字符串或可空类型。

 string s = someString ?? "Default message"; 

比…更容易

  string s; if(someString == null) s = "Default Message"; else s = someString; 

要么

  string s = someString != null ? someString : "Default Message"; 

我经常将它用于属性中的懒惰实例化对象,例如

 public MyObject MyProperty { get { return this.myField ?? (this.myField = new MyObject()); } } 

这利用了这样的事实:在C#中,赋值是一个表达式,因此您可以在同一语句中分配和使用表达式的结果(赋值)。 我仍然觉得这个代码模式略显肮脏,但它比替代方案(下面)更为简洁,所以它只是胜利。

 public MyObject MyProperty { get { if (this.myField == null) { this.myField = new MyObject(); } return this.myField; } } 

正如FYI一样,三元运算符从空合并运算符生成不同的IL序列。 第一个看起来像这样:

 // string s = null; // string y = s != null ? s : "Default"; ldloc.0 brtrue.s notnull1 ldstr "Default" br.s isnull1 notnull1: ldloc.0 isnull1: stloc.1 

而后者看起来像这样:

 // y = s ?? "Default"; ldloc.0 dup brtrue.s notnull2 pop ldstr "Default" notnull2: stloc.1 

基于此,我会说空合并运算符针对其目的进行了优化,而不仅仅是语法糖。

?? 实际上是一个空检查操作符。

您的代码遇到麻烦的原因是,如果“someObject为null,则.someMember是null对象上的属性。您必须首先检查someObject是否为null。

编辑:

我应该补充一点是,我确实找到了? 非常有用,特别是在处理数据库输入时,特别是从LINQ,但在其他情况下。 我大量使用它。

我一直在使用它与App.Config的东西

 string somethingsweet = ConfigurationManager.AppSettings["somesetting"] ?? "sugar"; 

最有用的是处理可空类型时。

 bool? whatabool; //... bool realBool = whatabool ?? false; 

没有? 你需要写下面的内容,这更令人困惑。

 bool realbool = false; if (whatabool.HasValue) realbool = whatabool.Value; 

我发现这个操作符对于可空类型非常有用,但除此之外我没有发现自己非常使用它。 绝对是一个很酷的捷径。

我使用它来处理在正常操作下可以返回null的方法。

例如,假设我有一个容器类,如果容器不包含密钥(或者null是有效关联),则该方法返回null。 然后我可能会做这样的事情:

 string GetStringRep(object key) { object o = container.Get(key) ?? "null"; return o.ToString(); } 

显然,这两个序列是等价的:

 foo = bar != null ? bar : baz; foo = bar ?? baz; 

第二个只是更简洁。

用更紧凑的forms替换冗长的语法通常似乎是一个好主意。 但通常最终只会混淆代码而不会真正获得任何东西。 现代标准提倡更长,更具描述性的变量名称,并使用更详细的布局样式,以使代码更易读,更易于维护。

如果我要训练我的大脑快速解析??,我需要找到一个显示出明显优势的情况 – 某些事情无法通过其他方式完成,或者某个地方可以节省大量的打字。

这是哪里? 对我来说倒下了。 它很有用而且很有用?:if if / else是如此快速和可读的替代方案,使用不同的语法实际上似乎没什么新意义。

a = b ?? C ?? d ?? Ë; 听起来很棒。 但我从来不需要这样做!

我觉得很烦人的是我想要使用??,但每次我都想“哦,也许我可以在这里使用”,我意识到我不想使用对象本身,而是它的成员。

name =(user == null)? “doe”:user.Surname;

不幸的是,?? 在这里没有帮助。

在您的情况下,您可以创建DefaultObject作为静态属性,并使用如下所示…

 var x = (someObject as someType ?? someType.DefaultObject).someMember; 

DefaultObject将返回静态的只读对象。

像EventArgs.Empty,String.Empty等…

我遇到了与你完全相同的问题,但是在使用LinqToXML的空间中,标签可能不在文档中,所以使用?? 对于标记该属性的财产是不可行的。

因为在C#中没有全局变量这样的东西所以在一个类中所以我发现,像你一样,那个? 大多没用。

即使是一个简单的属性getter,如:

 MyObject MyObj() { get { return _myObj ?? new MyObj(); } } 

初始化程序可能更好地服务…

我想像在SQL中一样,它在Linq查询中会有所帮助,但我现在无法真正推导出一个。

在将字符串解析为其他数据类型时,我经常使用null-coalescing运算符。 我有一组扩展方法,它们包含像Int32.TryParse这样的东西并返回一个可空的int,而不是将输出参数暴露给我的其余代码。 然后,我可以解析一个字符串,并在解析失败时提供一个默认值,在一行代码中。

 // ToNullableInt(), is an extension method on string that returns null // if the input is null and returns null if Int32.TryParse fails. int startPage = Request.QueryString["start"].ToNullableInt() ?? 0;