Уникальные способы использования оператора Null Coalescing - PullRequest
149 голосов
/ 10 ноября 2008

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

string nobody = null;
string somebody = "Bob Saget";
string anybody = "";

anybody = nobody   ?? "Mr. T"; // returns Mr. T
anybody = somebody ?? "Mr. T"; // returns "Bob Saget"

Но для чего еще можно использовать ??? Он не кажется таким полезным, как троичный оператор, кроме того, что он более лаконичен и удобен для чтения, чем:

nobody = null;
anybody = nobody == null ? "Bob Saget" : nobody; // returns Bob Saget

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

  • Вы использовали ?? для чего-то еще?

  • Является ли ?? необходимым, или вы должны просто использовать троичный оператор (который большинство знакомо с)

Ответы [ 16 ]

199 голосов
/ 10 ноября 2008

Ну, во-первых, гораздо проще связать, чем стандартную тройную:

string anybody = parm1 ?? localDefault ?? globalDefault;

против

string anyboby = (parm1 != null) ? parm1 
               : ((localDefault != null) ? localDefault 
               : globalDefault);

Это также хорошо работает, если нулевой объект не является переменной:

string anybody = Parameters["Name"] 
              ?? Settings["Name"] 
              ?? GlobalSetting["Name"];

против.

string anybody = (Parameters["Name"] != null ? Parameters["Name"] 
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];
173 голосов
/ 10 ноября 2008

Я использовал его как однострочник с отложенной загрузкой:

public MyClass LazyProp
{
    get { return lazyField ?? (lazyField = new MyClass()); }
}

читаемым? Решай сам.

51 голосов
/ 10 ноября 2008

Я нашел это полезным двумя «немного странными» способами:

  • В качестве альтернативы для параметра out при записи подпрограмм TryParse (т. Е. Возвращает нулевое значение в случае сбоя синтаксического анализа)
  • как представление "не знаю" для сравнений

Последнему нужно немного больше информации. Как правило, когда вы создаете сравнение с несколькими элементами, вам нужно посмотреть, дает ли первая часть сравнения (например, возраст) однозначный ответ, а затем следующую часть (например, имя), только если первая часть не помогла. Использование оператора объединения нулей означает, что вы можете писать довольно простые сравнения (для упорядочения или равенства). Например, используя пару вспомогательных классов в MiscUtil :

public int Compare(Person p1, Person p2)
{
    return PartialComparer.Compare(p1.Age, p2.Age)
        ?? PartialComparer.Compare(p1.Name, p2.Name)
        ?? PartialComparer.Compare(p1.Salary, p2.Salary)
        ?? 0;
}

По общему признанию, у меня теперь есть ProjectionComparer в MiscUtil, вместе с некоторыми расширениями, которые делают подобные вещи еще проще - но это все еще хорошо.

То же самое можно сделать для проверки ссылочного равенства (или недействительности) в начале реализации Equals.

32 голосов
/ 20 декабря 2008

Еще одним преимуществом является то, что троичный оператор требует двойной оценки или временной переменной.

Рассмотрим это, например:

string result = MyMethod() ?? "default value";

в то время как с троичным оператором у вас остается либо:

string result = (MyMethod () != null ? MyMethod () : "default value");

, который дважды вызывает MyMethod, или:

string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");

В любом случае, оператор слияния ноль чище и, я думаю, более эффективен.

20 голосов
/ 17 августа 2015

Следует также учитывать, что оператор coalesce не вызывает метод get свойства дважды, как это делает троичный оператор.

Таким образом, есть сценарии, в которых вы не должны использовать троичный, например:

public class A
{
    var count = 0;
    private int? _prop = null;
    public int? Prop
    {
        get 
        {
            ++count;
            return _prop
        }
        set
        {
            _prop = value;
        }
    }
}

Если вы используете:

var a = new A();
var b = a.Prop == null ? 0 : a.Prop;

получатель будет вызван дважды, а переменная count будет равна 2, и если вы используете:

var b = a.Prop ?? 0

переменная count будет равна 1, как и должно быть.

14 голосов
/ 28 ноября 2012

Самое большое преимущество, которое я нахожу для оператора ??, заключается в том, что вы можете легко преобразовывать типы значений NULL в типы NULL:

int? test = null;
var result = test ?? 0; // result is int, not int?

Я часто использую это в запросах Linq:

Dictionary<int, int?> PurchaseQuantities;
// PurchaseQuantities populated via ASP .NET MVC form.
var totalPurchased = PurchaseQuantities.Sum(kvp => kvp.Value ?? 0);
// totalPurchased is int, not int?
9 голосов
/ 11 ноября 2008

я использовал ?? в моей реализации IDataErrorInfo:

public string Error
{
    get
    {
        return this["Name"] ?? this["Address"] ?? this["Phone"];
    }
}

public string this[string columnName]
{
    get { ... }
}

Если какое-либо отдельное свойство находится в состоянии «ошибка», я получаю эту ошибку, в противном случае я получаю ноль. Работает очень хорошо.

7 голосов
/ 01 июля 2013

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

public void Method(Arg arg = null)
{
    arg = arg ?? Arg.Default;
    ...
6 голосов
/ 19 июня 2014

Мне нравится использовать оператор null coalesce для отложенной загрузки определенных свойств.

Очень простой (и надуманный) пример, чтобы проиллюстрировать мою точку зрения:

public class StackOverflow
{
    private IEnumerable<string> _definitions;
    public IEnumerable<string> Definitions
    {
        get
        {
            return _definitions ?? (
                _definitions = new List<string>
                {
                    "definition 1",
                    "definition 2",
                    "definition 3"
                }
            );
        }
    } 
}
5 голосов
/ 15 февраля 2011

Есть ?? необходимо, или вы должны просто использовать троичный оператор (с которым большинство знакомо)

На самом деле, мой опыт показывает, что слишком немногие знакомы с троичным оператором (или, точнее, условным оператором ; ?: является "троичным" в том же смысле, что и || двоичный или + является либо унарным, либо двоичным; однако, во многих языках он оказывается единственным тернарным оператором), поэтому, по крайней мере, в этом ограниченном примере ваше утверждение не будет выполнено прямо здесь.

Кроме того, как упоминалось ранее, существует одна важная ситуация, когда оператор слияния нуля очень полезен, и это когда всякий раз вычисляемое выражение имеет какие-либо побочные эффекты. В этом случае вы не можете использовать условный оператор без (а) введения временной переменной или (б) изменения фактической логики приложения. (б) явно не подходит ни при каких обстоятельствах, и хотя это личное предпочтение, мне не нравится загромождать область объявления множеством посторонних, даже если недолговечных переменных, поэтому (а) слишком конкретный сценарий.

Конечно, если вам нужно выполнить несколько проверок результата, условный оператор или набор if блоков, вероятно, являются инструментом для работы. Но для простого «если это ноль, используйте это, в противном случае используйте его», оператор слияния нуль ?? идеален.

...