我同意你的观点??运算符的用途通常有限——如果某些内容为空,则提供一个后备值很有用,但在您想继续深入了解有时的属性或方法的情况下,它对于防止空引用异常没有用处——空引用。
恕我直言,除了 ?? 还需要什么?是一个“空引用”运算符,它允许您将长属性和/或方法链链接在一起,例如a.b().c.d().e 无需测试每个中间步骤是否为空。 Groovy 语言有一个Safe Navigation operator,非常方便。
幸运的是,C# 团队似乎意识到了这个功能差距。请参阅此 connect.microsoft.com suggestion 以了解 C# 团队向 C# 语言添加 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);
}
}