Уникальные способы использования оператора Null Coalescing

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

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

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

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

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

Ответ 1

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

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"];

Ответ 2

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

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

читаемым? Решите для себя.

Ответ 3

Я нашел его полезным в двух "немного странных" способах:

  • В качестве альтернативы для параметра 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.

Ответ 4

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

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

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

в то время как с тернарным оператором вы также можете:

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

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

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

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

Ответ 5

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

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

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, как и должно быть.

Ответ 6

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

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?

Ответ 7

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

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

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

Если какое-либо индивидуальное свойство находится в состоянии "ошибки", я получаю эту ошибку, иначе я получаю null. Хорошо работает.

Ответ 8

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

public void Method(Arg arg = null)
{
    arg = arg ?? Arg.Default;
    ...

Ответ 9

Мне нравится использовать оператор 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"
                }
            );
        }
    } 
}

Ответ 10

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

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

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

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

Ответ 11

Только проблема - оператор null-coalesce не обнаруживает пустые строки.


то есть.

string result1 = string.empty ?? "dead code!";

string result2 = null ?? "coalesced!";

ВЫВОД:

result1 = ""

result2 = coalesced!

В настоящее время я смотрю на переопределение? чтобы обойти это. Конечно, было бы удобно иметь это встроенное в Framework.

Мысли?

Ответ 12

В последнее время я много чего делаю, используя null coalescing для резервного копирования до as. Например:

object boxed = 4;
int i = (boxed as int?) ?? 99;

Console.WriteLine(i); // Prints 4

Он также полезен для резервного копирования длинных цепочек ?., которые могли бы терпеть неудачу

int result = MyObj?.Prop?.Foo?.Val ?? 4;
string other = (MyObj?.Prop?.Foo?.Name as string)?.ToLower() ?? "not there";

Ответ 13

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

Вы должны использовать то, что лучше всего выражает ваши намерения. Поскольку существует нулевой оператор коалесценции, используйте его.

С другой стороны, поскольку он настолько специализирован, я не думаю, что он имеет другие цели. Я предпочел бы соответствующую перегрузку оператора ||, как это делают другие языки. Это было бы более скупым в оформлении языка. Но хорошо...

Ответ 14

Круто! Подсчитайте меня как человека, который не знал о нулевом коалесцирующем операторе - это довольно изящный материал.

Мне гораздо легче читать, чем тернарный оператор.

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

public void someMethod( object parm2, ArrayList parm3 )
{ 
  someMethod( null, parm2, parm3 );
}
public void someMethod( string parm1, ArrayList parm3 )
{
  someMethod( parm1, null, parm3 );
}
public void someMethod( string parm1, object parm2, )
{
  someMethod( parm1, parm2, null );
}
public void someMethod( string parm1 )
{
  someMethod( parm1, null, null );
}
public void someMethod( object parm2 )
{
  someMethod( null, parm2, null );
}
public void someMethod( ArrayList parm3 )
{
  someMethod( null, null, parm3 );
}
public void someMethod( string parm1, object parm2, ArrayList parm3 )
{
  // Set your default parameters here rather than scattered through the above function overloads
  parm1 = parm1 ?? "Default User Name";
  parm2 = parm2 ?? GetCurrentUserObj();
  parm3 = parm3 ?? DefaultCustomerList;

  // Do the rest of the stuff here
}

Ответ 15

Немного странного варианта использования, но у меня был метод, в котором объект IDisposable потенциально передается как arg (и, следовательно, его выбрано родителем), но может также быть нулевым (и поэтому должен быть создан и удален в локальном метод)

Чтобы использовать его, код выглядел как

Channel channel;
Authentication authentication;

if (entities == null)
{
    using (entities = Entities.GetEntities())
    {
        channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
        [...]
    }
}
else
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}

Но с нулевым коалесцентом становится намного опрятным

using (entities ?? Entities.GetEntities())
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}

Ответ 16

Я использовал так:

for (int i = 0; i < result.Count; i++)
            {
                object[] atom = result[i];

                atom[3] = atom[3] ?? 0;
                atom[4] = atom[4] != null ? "Test" : string.Empty;
                atom[5] = atom[5] ?? "";
                atom[6] = atom[6] ?? "";
                atom[7] = atom[7] ?? "";
                atom[8] = atom[8] ?? "";
                atom[9] = atom[9] ?? "";
                atom[10] = atom[10] ?? "";
                atom[12] = atom[12] ?? false; 
            }

Ответ 17

Оператор нуль-коалесценции

Этот оператор проверяет переменную, если ноль, возвращает значение рядом с '??' оператор иначе даст значение, сохраненное в переменной.

Например: -1

var name='ATHUL';
var result =name ?? 'The name is null'
Console.WriteLine(result);

o/p: ATHUL

Например: -2

var name=null;
var result =name ?? 'The name is null'
Console.WriteLine(result);

o/p: имя пустое