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

Лучший синтаксис для a = (x == null)? null: x.func()

Основной вопрос здесь - у меня много строк кода, которые выглядят примерно так:

var a = (long_expression == null) ? null : long_expression.Method();

Подобные линии многократно повторяют эту функцию. long_expression отличается каждый раз. Я пытаюсь найти способ избежать повторения long_expression, но сохраняя этот компактный. Что-то вроде противоположности operator ??. На данный момент я рассматриваю возможность сдачи и ввода нескольких строк, например:

var temp = long_expression;
var a = (temp == null) ? null : temp.Method();

Но мне было любопытно, есть ли какой-нибудь умный синтаксис, о котором я не знаю, что сделает его более кратким.

4b9b3361

Ответ 1

Ну, вы можете использовать метод расширения следующим образом:

public static TResult NullOr<TSource, TResult>(this TSource source,
    Func<TSource, TResult> func) where TSource : class where TResult : class
{
    return source == null ? null : func(source);
}

Тогда:

var a = some_long_expression.NullOr(x => x.Method());

Или (в зависимости от вашей версии С#)

var a = some_long_expression.NullOr(Foo.Method);

где Foo - тип some_long_expression.

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

Ответ 2

Я нашел этот ответ проницательным.

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

Вместо того, чтобы разрешить выполнение продолжить с нулями, замените нуль лучшим представлением (указанным по ссылке)

  • Если нуль представляет пустую коллекцию, используйте пустую коллекцию.
  • Если нуль представляет исключительный случай, выведите исключение.
  • Если значение null представляет собой случайно неинициализированное значение, явно инициализируйте его.
  • Если значение null представляет собой законное значение, проверьте его - или даже лучше используйте NullObject, который выполняет нулевой оператор.

В частности, замена ссылки на null-сборку пустой коллекцией спасла мне много нулевых тестов.

Ответ 3

var x = "";

/* try null instead */
string long_expression = "foo";

var a = ((x = long_expression) == null) ? null : x.ToUpper();

/* writes "FOO" (or nothing) followed by newline */
Console.WriteLine(a);

Тип значения инициализации x должен быть совместим с типом long_expression (здесь: string). Работает с Mono компилятор С#, версия 2.10.8.1 (из пакета Debian mono-gmcs = 2.10.8.1-4).

Ответ 4

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

Нам нужно что-то в строю "??" или "if null then", но работает как специальный. точечного оператора с условием "если не null". Во-первых '?' это как "if" часть "?:" if-then, а вторая "?" представляет "null" как для типов с нулевым значением. Я думаю, нам нужно ".?" оператор, который работает так же, как ".", за исключением того, что он просто вычисляет значение null, если левое выражение является нулевым, а не выбрасывает исключение. Я предполагаю, что это будет оператор "точка не нуль" (ОК, так что, возможно, ".!?" Было бы более логичным, но не пускай туда).

Итак, ваш пример oh-so-common может потерять избыточное имя символа, например:

var a = long_expression.?Method();

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

if (localObject != null)
{
    if (localObject.ChildObject != null)
    {
        if (localObject.ChildObject.ChildObject != null)
            localObject.ChildObject.ChildObject.DoSomething();
    }
}

может стать просто:

localObject.?ChildObject.?ChildObject.?DoSomething();

Существует также тонна кода, где нулевые проверки, которые должны быть там, отсутствуют, что приводит к случайным ошибкам во время выполнения. Итак, на самом деле, используя новый '.?' оператор по умолчанию устранит такие проблемы... Может быть, к сожалению, мы не можем изменить поведение ".". а также '.?' на данный момент, так что только новый ".?" выдает исключение, если левая сторона имеет нулевое значение - это будет более чистый и логичный путь, но нарушение изменений очень плохое. Хотя, можно утверждать, что это конкретное изменение, скорее всего, устранит множество скрытых проблем и вряд ли что-нибудь сломает (только код, ожидающий исключения null ref ref). О, ну... всегда можно мечтать...

Единственный недостаток проверки нулевого значения - это, пожалуй, небольшое повышение производительности, что, несомненно, является причиной того, почему '.' не проверяет значение null. Но я действительно думаю, что можно просто использовать ".?" когда вы заботитесь о производительности (и знаете, что левая сторона никогда не будет равна нулю), было бы лучшим способом.

Аналогичным образом было бы гораздо приятнее иметь "foreach" проверку и игнорирование нулевой коллекции. Больше не нужно обертывать большинство "foreach" операторов "if (collection!= Null)" или, что еще хуже, развивать обычную привычку всегда использовать пустые коллекции вместо нуля... что в некоторых случаях прекрасно, но еще хуже чем нулевая проверка, когда это делается в сложных деревьях объектов, где большая часть коллекций пуста (что я видел много). Я думаю, что хорошее намерение не иметь проверку "foreach" для получения нулевого значения, чтобы обеспечить лучшую производительность, в большинстве случаев отрицательно сказалось.

Андерс, никогда не поздно делать такие изменения, и добавить для них компилятор!

Ответ 5

Вы можете написать метод расширения для любого типа long_expression:

public static object DoMethod(this MyType pLongExpression)
{
   return pLongExpression == null ? null : pLongExpression.Method();
}

Это будет доступно для любой ссылки MyType, даже если эта ссылка null.

Ответ 6

Вы можете поместить long_expression == null в функцию с коротким именем и просто вызвать эту функцию каждый раз.

Ответ 7

if (! String.IsNullOrEmpty(x))   x.func()