Уникальные способы использования нуль-Коалесцирующий оператора



Я знаю, что стандартный способ использования оператора коалесценции Null в 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


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




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


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


585   16  

16 ответов:

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

string anybody = parm1 ?? localDefault ?? globalDefault;

и

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

Он также хорошо работает, если значение null-объект не является переменной:

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

и

string anybody = (Parameters["Name"] != null ? Parameters["Name"] 
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];

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

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

чтения? Решить для себя.

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

  • в качестве альтернативы, имеющей

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

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

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

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

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

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

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

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

еще одна вещь, которую следует учитывать, заключается в том, что оператор 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

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

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

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?

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

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

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

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

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

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

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

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

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

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

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


т. е.

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

string result2 = null ?? "coalesced!";

выход:

result1 = ""

result2 = coalesced!

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

мысли?

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

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

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

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

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

Я нахожу его гораздо легче читать, чем тернарный оператор.

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

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
}

одна вещь, которую я делал много в последнее время, - это использование 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";

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

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

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);
    [...]
}

Нуль-Коалесцирующий Оператор

этот оператор проверяет переменную, если null, возвращает значение рядом с "??"оператор else дает значение, сохраненное в переменной.

например:-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: имя null

Comments

    Ничего не найдено.