Подтвердить что ты не робот

Выражение С# if-null-then-null

Просто для любопытства/удобства: С# предоставляет две классные функции условного выражения, которые я знаю:

string trimmed = (input == null) ? null : input.Trim();

и

string trimmed = (input ?? "").Trim();

Я пропустил еще одно такое выражение для ситуации, с которой я сталкиваюсь очень часто:

Если исходная ссылка имеет значение NULL, то вывод должен быть нулевым. В противном случае результат должен быть результатом доступа к методу или свойству входного объекта.

Я сделал именно это в моем первом примере, но (input == null) ? null : input.Trim() довольно многословный и нечитаемый.

Есть ли другое условное выражение для этого случая или я могу использовать оператор ?? элегантно?

4b9b3361

Ответ 1

Что-то вроде Groovy нуль-безопасный оператор разыменования?

string zipCode = customer?.Address?.ZipCode;

Я понимаю, что команда С# посмотрела на это и обнаружила, что он не так прост в дизайне элегантно, как можно было бы ожидать... хотя я не слышал о деталях проблем.

Я не верю, что на этом языке есть такая вещь, я боюсь... и я не слышал о каких-либо планах, хотя это не означает, что этого не произойдет точка.

EDIT: теперь он будет частью С# 6, как "оператор с нулевым условием".

Ответ 2

Вы можете выбрать между настраиваемым 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 );

Ответ 3

В настоящее время мы можем написать только метод расширения, если вы не хотите повторять себя, я боюсь.

public static string NullableTrim(this string s)
{
   return s == null ? null : s.Trim();
}

Ответ 4

В качестве обходного пути вы можете использовать это, основанное на Возможно, монада.

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());

Ответ 5

Нет ничего встроенного, но вы могли бы обернуть все это в метод расширения, если хотите (хотя я, вероятно, не стал бы беспокоиться).

Для этого конкретного примера:

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);
    }
}

Ответ 6

У меня была та же проблема, что я написал несколько небольших методов расширения:

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());

Существуют также перегрузки для типов с нулевым значением.