我同意你的观点??运算符的用途通常有限——如果某些内容为空,则提供后备值很有用,但在您想继续深入研究有时的属性或方法时,它对于防止空引用异常没有用处 -空引用。
恕我直言,还需要什么?是一个“空引用”运算符,它允许您将长属性和/或方法链链接在一起,例如a.b().c.d().e
,无需测试每个中间步骤的空值。Groovy语言有一个安全导航运算符,非常方便。
幸运的是,C# 团队似乎意识到了这个功能差距。请参阅此connect.microsoft.com 建议C# 团队向 C# 语言添加空取消引用运算符。
我们收到了很多与此类似的功能的请求。这 ”?。” 社区讨论中提到的版本最贴近我们的心——它允许您在每个“点”处测试 null,并与现有的 ?? 操作员:
a?.b?.c?? d
这意味着如果 a 、 ab 或 abc 中的任何一个为空,请使用 d 代替。
我们正在考虑将其用于未来的版本,但不会出现在 C# 4.0 中。
再次感谢,
Mads Torgersen,C# 语言 PM
如果您还希望在 C# 中使用此功能,请在连接站点上为建议添加您的投票!:-)
我用来解决缺少此功能的一种解决方法是使用扩展方法,如本博客文章中描述的那样,以允许这样的代码:
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);
}
}