Я согласен с вами в том, что ?? оператор, как правило, ограниченного использования. Полезно предоставить значение возврата, если что-то имеет значение NULL, но не является полезным для предотвращения исключения Null Reference в случаях, когда вы хотите продолжить сверление свойств или методов, null ссылка.
ИМХО, что нужно гораздо больше, чем ??? является оператором «null-dereference», который позволяет вам объединять длинные цепи свойств и/или методов вместе, например. a.b().c.d().e
без проверки каждого промежуточного шага для нулевого значения. Язык Groovy имеет Safe Navigation operator, и это очень удобно.
К счастью, похоже, что команда C# знает об этом недостатке. См. Это connect.microsoft.com suggestion для команды C#, чтобы добавить оператор нулевой разницы на язык C#.
Мы получаем довольно много запросов для функций, подобных этому. «?». версия, упомянутая в сообществе обсуждение ближе всего к нашим сердцам - это позволяет проверить значение нуля на каждой «точки» и красиво складывается с существующих? оператор:
a? .b? .c ?? d
Значение, если какой-либо из a, a.b или a.b.c имеет значение , вместо этого использовать d вместо d.
Мы рассматриваем это для будущего выпуска , но его не будет в C# 4.0.
Еще раз спасибо,
Мадс Торгерсен, C# Язык PM
Если вы хотите эту функцию в C#, добавить свои голоса в suggestion на подключения сайте! :-)
Один из способов я использую, чтобы обойти отсутствие этой функции является метод расширения, как то, что описано в this blog post, чтобы такой код:
string s = h.MetaData
.NullSafe(meta => meta.GetExtendedName())
.NullSafe(s => s.Trim().ToLower())
Этот код возвращает либо h.MetaData.GetExtendedName().Trim().ToLower()
или возвращает null, если h, h.MetaData или h.MetaData.GetExtendedName() - 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);
}
}
FYI: ?? называется нулевым коалесцирующим оператором. –
Да, именно то, что я думаю. – Ruben
Я думаю, что это должна быть «вики сообщества». –