C#, если-нуль, то значение выражения
просто для любопытства / удобства: C# предоставляет две интересные функции условного выражения, о которых я знаю:
string trimmed = (input == null) ? null : input.Trim();
и
string trimmed = (input ?? "").Trim();
мне не хватает еще одного такого выражения для ситуации, с которой я сталкиваюсь очень часто:
если входная ссылка равна нулю, то выход должен быть равен нулю. В противном случае выходные данные должны быть результатом доступа к методу или свойству объекта ввода.
Я сделал именно это в моем первом примере, но (input == null) ? null : input.Trim()
довольно многословно и нечитабельно.
есть еще одно условное выражение для этого случая, или я могу использовать ??
оператор элегантно?
6 ответов:
что-то вроде нулевого безопасного оператора разыменования Groovy?
string zipCode = customer?.Address?.ZipCode;
Я так понимаю, что команда C# посмотрела на это и обнаружила, что это не так просто, чтобы проектировать элегантно, как можно было бы ожидать... хотя я не слышал о проблемах.
боюсь, что сейчас в языке нет ничего подобного... и я не слышал о каких-либо планах на это, хотя это не значит, что это не произойдет в какой-то момент точка.
EDIT: теперь он будет частью C# 6, как "оператор null-conditional".
вы можете выбрать между пользовательским
Nullify
илиNullSafe
метод расширения, как описано здесь: http://qualityofdata.com/2011/01/27/nullsafe-dereference-operator-in-c/использование будет следующим:
//Groovy: bossName = Employee?.Supervisor?.Manager?.Boss?.Name //C# Option 1: bossName = Nullify.Get(Employee, e => e.Supervisor, s => s.Manager, m => m.Boss, b => b.Name); //C# Option 2: bossName = Employee.NullSafe( e => e.Supervisor ).NullSafe( s => s.Boss ) .NullSafe( b => b.Name );
в настоящее время мы можем только написать метод расширения, если вы не хотите повторяться, я боюсь.
public static string NullableTrim(this string s) { return s == null ? null : s.Trim(); }
в качестве обходного пути вы можете использовать это, которая основана на может быть, монада.
public static Tout IfNotNull<Tin, Tout>(this Tin instance, Func<Tin, Tout> Output) { if (instance == null) return default(Tout); else return Output(instance); }
использовать его таким образом:
int result = objectInstance.IfNotNull(r => 5); var result = objectInstance.IfNotNull(r => r.DoSomething());
нет ничего встроенного, но вы можете обернуть все это в метод расширения, если хотите (хотя я, вероятно, не буду беспокоиться).
для этого конкретного примера:
string trimmed = input.NullSafeTrim(); // ... public static class StringExtensions { public static string NullSafeTrim(this string source) { if (source == null) return source; // or return an empty string if you prefer return source.Trim(); } }
или более универсальная версия:
string trimmed = input.IfNotNull(s => s.Trim()); // ... public static class YourExtensions { public static TResult IfNotNull<TSource, TResult>( this TSource source, Func<TSource, TResult> func) { if (func == null) throw new ArgumentNullException("func"); if (source == null) return source; return func(source); } }
у меня была та же проблема, я написал несколько небольших методов расширения:
public static TResult WhenNotNull<T, TResult>( this T subject, Func<T, TResult> expression) where T : class { if (subject == null) return default(TResult); return expression(subject); } public static TResult WhenNotNull<T, TResult>( this T subject, Func<T, TResult> expression, TResult defaultValue) where T : class { if (subject == null) return defaultValue; return expression(subject); } public static void WhenNotNull<T>(this T subject, Action<T> expression) where T : class { if (subject != null) { expression(subject); } }
вы используете его так;
string str = null; return str.WhenNotNull(x => x.Length);
или
IEnumerable<object> list; return list.FirstOrDefault().WhenNotNull(x => x.id, -1);
или
object obj; IOptionalStuff optional = obj as IOptionalStuff; optional.WhenNotNull(x => x.Do());
существуют также перегрузки для типов с нулевым значением.