2015-01-13 3 views
23

Я наткнулся на интересный сайт, на котором рассматриваются некоторые из новых (предлагаемых) функций C# 6.0. Вы можете прочитать его здесь: Probable C# 6.0 features.Monadic null check in 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-распространения является то, что он будет оценивать оператор только один раз. Однако (возможно, из-за моего незнания CLR), мне очень любопытно, как это можно выполнить.
    Что касается меня, то первая оценка (если точки равны нулю) должна инициировать метод расширения FirstOrDefault() для запуска, когда точки не являются нулевыми, а затем оценка возвращаемого типа должна быть нулевой или нет, если нет, X будут возвращены. Значит, это три оценки в сочетании с одной? Или я понимаю это неправильно? Это повлияет на скорость исполнения?

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

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

EDIT
Как Мэтью Уотсон предоставил хороший MSDN article обсуждение этого (и более) темы (ы), мне было интересно, если он упомянул мой предыдущий вопрос о неограниченных дженерик и как этот оператор имеет дело с этим. К сожалению, я еще не нашел ответа. Хотя я буду предполагать, что программист должен попытаться предотвратить использование неконституционных дженериков, я все же могу предположить, что это иногда невозможно. Если это так, будет ли необходимость в редизайне?

+2

Теперь он называется [«Null условный оператор»] (http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx). –

+1

Здесь вы найдете много информации https://roslyn.codeplex.com/discussions/540883. – adrianm

+2

@MatthewWatson 'if (MyEvent! = Null) MyEvent (this, EventArgs.Empty);' является хорошо известным примером того, что должно быть переписано как «var myEvent = MyEvent; if (myEvent! = null) myEvent (this, EventArgs.Empty); ': даже если доступ к' MyEvent' является атомарным, он может меняться от ненулевого значения до нуля между сравнением и вызовом. Это то, что «MyEvent» .Invoke (this, EventArgs.Empty); 'должен обращаться уже, как я понимаю. – hvd

ответ

14

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

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

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

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

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

+3

Действительно ли это необходимо? Я не думаю, что кто-то ожидает, что 'x? .f' магически сделает' f' threadsafe. Он просто спрашивал: «x? .f» удаляет условие гонки в 'if (x.f! = Null) x.f'. – Rawling

+4

Я слышал это до того, что я переусердствую. Даже моя жена жалуется на это. Я думаю, что есть что-то делать, что я пытаюсь понять, как работают механики, прежде чем пытаться их использовать. @Rawling прав, что я имел в виду с моим первым вопросом. Я отредактирую свой вопрос. – RvdV79

+0

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

1

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

6

Чтобы частично ответить на первый вопрос, в соответствии с John Skeet on his blog нулевой оператор-оператор ?. (= оператор распространения null) является потокобезопасным.

+0

как безопасен поток операторов, если автор блога упоминает использование Interlocked.CompareExchange, чтобы сделать его потокобезопасным? Я имею в виду, что это возможно, но я не видел никаких доказательств этого в опубликованном блоге, я что-то пропустил? –

+1

«Код, который у нас есть до сих пор, является« потокобезопасным », поскольку не имеет значения, что делают другие потоки - вы не получите исключение NullReferenceException из вышеуказанного кода». Между тем, «Interlocked.CompareExchange» полезен «для вызова абсолютного последнего набора подписчиков событий». Таким образом, речь идет не о безопасности потоков, а о том, хотите ли вы обеспечить, чтобы событие было запущено на самом последнем наборе подписчиков событий. –

+0

Оператор в основном оценивает метод, который принимает x, проверяет значение null, а если нет null, он выполняет следующий код на x. Если вы вызовете метод с переменной-членом и переменной-членом сразу после того, как установлено значение null, переменная в вашем методе будет по-прежнему иметь фактический объект. В этом смысле ?. является потокобезопасным. –