Монадическая проверка на ноль в C# 6.0

Я наткнулся на интересный сайт, где рассматриваются некоторые из новых (предлагаемых) функций C# 6.0. Вы можете прочитать это здесь: Возможные возможности C# 6.0.

Что мне особенно интересно, так это монадическая проверка нуля (также известная как оператор распространения нуля ?). По данным сайта, следующее заявление

var bestValue = points?.FirstOrDefault()?.X ?? -1;

содержит монадическую проверку нуля, которая в настоящее время реализована с помощью этого фрагмента кода:

if (points != null) 
{
  var next = points.FirstOrDefault();
  if (next != null && next.X != null) return next.X;
}   
return -1;

Мой первый взгляд был, эй, что, черт возьми, здесь написано? Но после просмотра "старого" кода мне это начинает нравиться.

Тем не менее, я также начинаю получать некоторые вопросы, которые я хотел бы задать.

  • Я предполагаю, что этот распространяющий нуль оператор является потокобезопасным. Но как это на самом деле выполняется? Будут ли отменены условия гонки или они сохраняются?
  • Как этот оператор будет обрабатывать универсальные типы? Кроме того, как это будет иметь дело с неограниченными родовыми типами? Например, рассмотрим

    var resultAfterNullCheck = x?.Y;
    

    Если тип Y здесь создается с использованием ссылочных типов, типов значений, не допускающих значения NULL, и типов значений, допускающих значение NULL, то в этом нет ничего разумного (поскольку я не могу думать о том, что делать, поскольку я просто не знаю, что делать). Так есть ли значение по умолчанию, которое будет возвращено? Или это выдаст ошибку?

  • Рассматривая пример, который предоставляет сайт (и который я скопировал выше), я предполагаю, что одним из основных преимуществ оператора распространения нуль будет то, что он будет оценивать утверждение только один раз. Однако (возможно, из-за моего незнания CLR) мне довольно любопытно, как это можно сделать.
    Что касается меня, первая оценка (если точки равны нулю) должна инициировать метод расширения FirstOrDefault() для запуска, когда точки не равны нулю, с последующей оценкой возвращаемого типа, чтобы быть нулевым или нет, если нет, X будет вернулся. Таким образом, это на самом деле три оценки объединены в одну? Или я неправильно понимаю? Повлияет ли это на скорость исполнения?

Другими словами, что будет быстрее, старый способ выполнения нулевых проверок или этот новый прекрасный оператор? Я попытаюсь проверить это, выполнив некоторые исследования, как только загрузка Visual Studio 2015 будет завершена... Но для этого нужно немного терпения...

Есть какие-нибудь мысли по поводу этого нового типа оператора? Это действительно все еще предложенный вариант, или мы действительно можем рассчитывать на работу с этой новой монадической нулевой проверкой?

РЕДАКТИРОВАТЬ
Поскольку Мэтью Уотсон представил хорошую статью на MSDN, в которой обсуждается эта (и более) тема (я), мне было любопытно упомянуть мой предыдущий вопрос о неограниченных генериках и о том, как этот оператор справляется с этим. К сожалению, я еще не нашел ответ. Хотя я предполагаю, что программист должен попытаться предотвратить использование неограниченных обобщений, я все же могу представить, что это иногда неосуществимо. Если это так, будет ли реструктуризация действительно необходимой?

3 ответа

Решение

Вы слишком обдумываете это. Один за другим ваши вопросы:

  1. Почему вы предполагаете, что это потокобезопасный? Вызов функции-члена не является. Это не что иное, как вызов функции-члена с предварительной проверкой на нулевые значения, поэтому вы получаете столько безопасности потоков, сколько гарантирует исходная функция.

  2. Если ваш универсальный тип допускает нулевое сравнение (это то, что этот оператор будет использовать за кулисами), тогда будет генерироваться код. Если нет, вы получите ошибку компиляции (например, если вы хотите, чтобы тип был типом значения). Это охватывает все случаи!

  3. Он вызывается один раз для каждого оператора, как обычно . оператор. Если вы говорите A.b.c это все еще будет два уровня косвенности, и использование этого нового оператора ничем не отличается, он просто проверяет также на нулевые значения.

Реальные преимущества ?. в том, что он семантический (вы можете сразу увидеть, что пытается сделать ваш код) и короткое замыкание (делает код намного короче, чем вложенный) ifс). Вы не собираетесь заменять каждый . в вашем старом коде с ?.на самом деле вы, вероятно, будете использовать его редко. Но есть случаи, когда это будет полезно, как в следующих выражениях Linq ...OrDefault() операции или вызов событий.

Чтобы частично ответить на ваш первый вопрос, по словам Джона Скита в его блоге, нулевой условный оператор ?. (= нулевой оператор распространения) является потокобезопасным.

Вы можете найти все о запланированных функциях в обсуждении проекта Roslyn. Вы также можете попробовать новые функции в консольном приложении, используя Roslyn, например, nuget-пакет (это означает, что он работает с Visual Studio 2013 <)

Другие вопросы по тегам