所以我一直对这个感兴趣?运营商,但仍然无法使用它。当我做的事情时,我通常会想到它:
var x = (someObject as someType).someMember;
如果someObject有效且someMember为null,我可以
var x = (someObject as someType).someMember ?? defaultValue;
但是当someObject为null时,我几乎总是遇到问题,而且??并没有帮助我使这个更清洁,而不是自己做空检查。
你们找到了什么用途?在实际情况中?
答案 0 :(得分:32)
??
运算符与SQL中的coalesce方法类似,它为您提供第一个非空值。
var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue;
答案 1 :(得分:27)
我同意你的看法?运算符通常用途有限 - 如果某些内容为空,则提供后备值非常有用,但如果您希望继续向下钻取有时属性或方法,则无法防止出现空引用异常。空引用。
恕我直言,还需要什么呢?是一个“null-dereference”运算符,它允许您将长属性和/或方法链链接在一起,例如, a.b().c.d().e
,无需测试每个中间步骤的无效性。 Groovy语言有Safe Navigation operator,非常方便。
幸运的是,C#团队似乎意识到了这个功能差距。请参阅此connect.microsoft.com suggestion以便C#团队向C#语言添加null-dereference运算符。
我们收到了很多请求 与此类似的功能。 “?” 社区中提到的版本 讨论最贴近我们的心 - 它允许你测试null 每一个“点”,并与之很好地合作 现有的?操作者:
a?.b?.c ?? d
如果a,a.b或a.b.c中的任何一个是有意义的 null使用d代替。
我们正在考虑这个未来 发布,但它不会在C#4.0中。
再次感谢,
Mads Torgersen,C#语言PM
如果您还想在C#中使用此功能,请将您的投票添加到连接网站上的suggestion! : - )
我用来解决缺少此功能的一种解决方法是像this blog post中描述的扩展方法,以允许这样的代码:
string s = h.MetaData
.NullSafe(meta => meta.GetExtendedName())
.NullSafe(s => s.Trim().ToLower())
如果h,h.MetaData或h.MetaData.GetExtendedName()为null,则此代码返回h.MetaData.GetExtendedName().Trim().ToLower()
或返回null。我还扩展了它以检查null或空字符串,或null或空集合。这是我用来定义这些扩展方法的代码:
public static class NullSafeExtensions
{
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="TResult">resulting type of the expression</typeparam>
/// <typeparam name="TCheck">type of object to check for null</typeparam>
/// <param name="check">value to check for null</param>
/// <param name="valueIfNotNull">delegate to compute if check is not null</param>
/// <returns>null if check is null, the delegate's results otherwise</returns>
public static TResult NullSafe<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNull)
where TResult : class
where TCheck : class
{
return check == null ? null : valueIfNotNull(check);
}
/// <summary>
/// Tests for null/empty strings without re-computing values or assigning temporary variables
/// </summary>
/// <typeparam name="TResult">resulting type of the expression</typeparam>
/// <param name="check">value to check for null</param>
/// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
/// <returns>null if check is null, the delegate's results otherwise</returns>
public static TResult CheckNullOrEmpty<TResult>(this string check, Func<string, TResult> valueIfNotNullOrEmpty)
where TResult : class
{
return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check);
}
/// <summary>
/// Tests for null/empty collections without re-computing values or assigning temporary variables
/// </summary>
/// <typeparam name="TResult">resulting type of the expression</typeparam>
/// <typeparam name="TCheck">type of collection or array to check</typeparam>
/// <param name="check">value to check for null</param>
/// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
/// <returns>null if check is null, the delegate's results otherwise</returns>
public static TResult CheckNullOrEmpty<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNullOrEmpty)
where TCheck : ICollection
where TResult : class
{
return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check);
}
}
答案 2 :(得分:22)
我通常将它用于字符串或可空类型。
string s = someString ?? "Default message";
比
更容易 string s;
if(someString == null)
s = "Default Message";
else
s = someString;
或
string s = someString != null ? someString : "Default Message";
答案 3 :(得分:11)
我经常将它用于属性中的延迟实例化对象,例如
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;
}
}
答案 4 :(得分:8)
正如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
基于此,我会说空合并算子针对其目的进行了优化,而不仅仅是语法糖。
答案 5 :(得分:7)
??是一个空检查操作符,实际上。
你的代码遇到麻烦的原因是,如果“someObject为null,则.someMember是null对象上的属性。你必须首先检查someObject是否为null。
编辑:
我应该补充一点是,我确实找到了?非常有用,特别是在处理数据库输入时,特别是从LINQ,但在其他情况下。我大量使用它。
答案 6 :(得分:3)
我一直在使用它与App.Config的东西
string somethingsweet = ConfigurationManager.AppSettings["somesetting"] ?? "sugar";
答案 7 :(得分:2)
最有用的是处理可空类型时。
bool? whatabool;
//...
bool realBool = whatabool ?? false;
没有?你需要写下面的内容,这更令人困惑。
bool realbool = false;
if (whatabool.HasValue)
realbool = whatabool.Value;
我发现这个运算符对于可空类型非常有用,但除此之外我并没有发现自己非常使用它。绝对是一个很酷的捷径。
答案 8 :(得分:1)
在您的情况下,您可以将DefaultObject创建为静态属性,并使用如下...
var x = (someObject as someType ?? someType.DefaultObject).someMember;
DefaultObject将返回一个静态的只读对象。
与EventArgs.Empty,String.Empty等相似......
答案 9 :(得分:1)
我使用它来处理在正常操作下可以返回null的方法。
例如,假设我有一个容器类,如果容器不包含密钥(或者null是有效关联),则该方法具有返回null的Get方法。然后我可能会这样做:string GetStringRep(object key) {
object o = container.Get(key) ?? "null";
return o.ToString();
}
显然,这两个序列是等价的:
foo = bar != null ? bar : baz;
foo = bar ?? baz;
第二个只是更简洁。
答案 10 :(得分:1)
用更紧凑的形式替换冗长的语法通常似乎是个好主意。但通常最终只会混淆代码而不会真正获得任何东西。现代标准提倡更长和更具描述性的变量名称,并使用更详细的布局样式,以使代码更具可读性和可读性。更易于维护。
如果我要训练我的大脑快速解析??,我需要找到一种显示出明显优势的情况 - 这种情况不能以另一种方式完成,或者它可以节省大量的打字。
这是哪里?对我不利。它非常有用而且很有用?:if if / else是如此快速和可读的替代方案,使用不同的语法实际上似乎没有什么意义。
a = b ?? C ?? d ?? Ë;听起来很棒。但我从来不需要这样做!
我感到恼火的是我想要使用??,但每次我都想“噢,也许我可以在这里使用”,我意识到我不想使用对象本身,而是它的成员。
name =(user == null)? “doe”:user.Surname;
不幸的是,??在这里没有帮助。
答案 11 :(得分:0)
我遇到了与你完全相同的问题,但是在使用LinqToXML的空间中,标签可能不在文档中,因此使用??
对于标记该标记上的属性是不可行的。
由于在C#中没有全局变量这样的东西,所以一切都在一个类中,所以我发现,像你一样,那个?几乎没用。
即使是一个简单的属性getter,如:
MyObject MyObj() { get { return _myObj ?? new MyObj(); } }
初始化程序可能更好地服务...
我想像在SQL中一样,它在Linq查询中会有所帮助,但我现在无法真正推导出它。
答案 12 :(得分:0)
在将字符串解析为其他数据类型时,我经常使用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;