Выражение C# if-null-then-null
просто для любопытства / удобства: C# предоставляет две интересные функции условного выражения, которые я знаю:
string trimmed = (input == null) ? null : input.Trim();
и
string trimmed = (input ?? "").Trim();
мне не хватает еще одного такого выражения для ситуации, с которой я сталкиваюсь очень часто:
если входная ссылка null, то выход должен быть null. В противном случае вывод должен быть итогом обращении к методу или свойству объекта ввода.
Я сделал именно это в моем первом примере, но (input == null) ? null : input.Trim()
довольно многословно и нечитабельно.
есть еще одно условное выражение для этого случая, или я могу использовать ??
оператор элегантно?
6 ответов
что-то вроде нулевого безопасного оператора разыменования Groovy?
string zipCode = customer?.Address?.ZipCode;
Я полагаю, что команда C# посмотрела на это и обнаружила, что это не так просто элегантно, как можно было бы ожидать... хотя я не слышал о проблемах.
вы можете выбрать между пользовательским 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());
существуют также перегрузки для типов nullable.