Подтвердить что ты не робот

Насколько полезен С#? оператор?

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

var x = (someObject as someType).someMember;

Если someObject действителен, а someMember - null, я мог бы сделать

var x = (someObject as someType).someMember ?? defaultValue;

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

Что вы использовали для ребята? в практических ситуациях?

4b9b3361

Ответ 1

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

ИМХО, что нужно гораздо больше, чем??? является оператором "null-dereference", который позволяет вам объединять длинные цепи свойств и/или методов вместе, например. a.b().c.d().e без проверки каждого промежуточного шага для нулевого значения. В Groovy есть оператор безопасной навигации и это очень удобно.

К счастью, кажется, что команда С# знает об этом недостатке. См. Это сообщение connect.microsoft.com для команды С#, чтобы добавить оператор нулевой разницы на язык С#.

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

a?.b?.c?? д

Значение, если любой из a, a.b или a.b.c является null вместо этого используйте d.

Мы рассматриваем это для будущего релиз, но он не будет в С# 4.0.

Еще раз спасибо,

Мадс Торгерсен, язык С# PM

Если вы также хотите эту функцию на С#, добавьте свои голоса в предложение на сайте подключения!: -)

Одним из способов обхода недостатка этой функции является метод расширения, например, описанный в этот пост в блоге, чтобы разрешить код например:

string s = h.MetaData
            .NullSafe(meta => meta.GetExtendedName())
            .NullSafe(s => s.Trim().ToLower())

Этот код возвращает h.MetaData.GetExtendedName().Trim().ToLower() или возвращает значение null, если h, h.MetaData или h.MetaData.GetExtendedName() равно null. Я также расширил это, чтобы проверить нулевые или пустые строки, или пустые или пустые коллекции. Здесь код, который я использую для определения этих методов расширения:

public static class NullSafeExtensions
{
    /// <summary>
    /// Tests for null objects without re-computing values or assigning temporary variables.  Similar to 
    /// Groovy "safe-dereference" operator .? which returns null if the object is null, and de-references
    /// if the object is not null.
    /// </summary>
    /// <typeparam name="TResult">resulting type of the expression</typeparam>
    /// <typeparam name="TCheck">type of object to check for null</typeparam>
    /// <param name="check">value to check for null</param>
    /// <param name="valueIfNotNull">delegate to compute if check is not null</param>
    /// <returns>null if check is null, the delegate results otherwise</returns>
    public static TResult NullSafe<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNull)
        where TResult : class
        where TCheck : class
    {
        return check == null ? null : valueIfNotNull(check);
    }

    /// <summary>
    /// Tests for null/empty strings without re-computing values or assigning temporary variables
    /// </summary>
    /// <typeparam name="TResult">resulting type of the expression</typeparam>
    /// <param name="check">value to check for null</param>
    /// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
    /// <returns>null if check is null, the delegate results otherwise</returns>
    public static TResult CheckNullOrEmpty<TResult>(this string check, Func<string, TResult> valueIfNotNullOrEmpty)
        where TResult : class
    {
        return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check);
    }
    /// <summary>
    /// Tests for null/empty collections without re-computing values or assigning temporary variables
    /// </summary>
    /// <typeparam name="TResult">resulting type of the expression</typeparam>
    /// <typeparam name="TCheck">type of collection or array to check</typeparam>
    /// <param name="check">value to check for null</param>
    /// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
    /// <returns>null if check is null, the delegate results otherwise</returns>
    public static TResult CheckNullOrEmpty<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNullOrEmpty)
        where TCheck : ICollection
        where TResult : class
    {
        return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check);
    }
}

Ответ 2

Оператор ?? похож на метод coalesce в SQL, он получает первое ненулевое значение.

var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue;

Ответ 3

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

string s = someString ?? "Default message";

проще, чем

   string s;
   if(someString == null)
     s = "Default Message";         
   else
     s = someString;

или

  string s = someString != null ? someString : "Default Message";

Ответ 4

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

public MyObject MyProperty
{
    get
    {
        return this.myField ?? (this.myField = new MyObject());
    }
}

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

public MyObject MyProperty
{
    get
    {
        if (this.myField == null)
        {
            this.myField = new MyObject();
        }

        return this.myField;
    }
}

Ответ 5

?? фактически является оператором нулевой проверки.

Причина, по которой ваш код попадает в проблему, заключается в том, что если "someObject имеет значение null, то .someMember является свойством на нулевом объекте. Сначала вам нужно проверить someObject на null.

EDIT:

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

Ответ 6

Подобно FYI, тернарный оператор генерирует другую последовательность IL от оператора нулевой коалесценции. Первый выглядит примерно так:

// string s = null;
// string y = s != null ? s : "Default";
    ldloc.0
    brtrue.s notnull1
    ldstr "Default"
    br.s isnull1
    notnull1: ldloc.0
    isnull1: stloc.1

И последнее выглядит так:

// y = s ?? "Default";
    ldloc.0
    dup
    brtrue.s notnull2
    pop
    ldstr "Default"
    notnull2: stloc.1

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

Ответ 7

Я использую его с материалами App.Config

string somethingsweet = ConfigurationManager.AppSettings["somesetting"] ?? "sugar";

Ответ 8

Наиболее полезным является использование типов с нулевым значением.

bool? whatabool;
//...
bool realBool = whatabool ?? false;

без? вам нужно будет написать следующее, что гораздо более запутанно.

bool realbool = false;
if (whatabool.HasValue)
    realbool = whatabool.Value;

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

Ответ 9

В вашем случае вы можете создать DefaultObject как статическое свойство и использовать, как показано ниже...

var x = (someObject as someType ?? someType.DefaultObject).someMember;

Если ваш DefaultObject вернет статический объект только для чтения.

Как EventArgs.Empty, String.Empty и т.д.

Ответ 10

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

например, допустим, что у меня есть класс контейнера, который имеет метод Get, который возвращает значение null, если контейнер не содержит ключа (или, может быть, null является допустимой ассоциацией). Тогда я мог бы сделать что-то вроде этого:

string GetStringRep(object key) {
    object o = container.Get(key) ?? "null";
    return o.ToString();
}

ясно, что эти две последовательности эквивалентны:

foo = bar != null ? bar : baz;
foo = bar ?? baz;

Во-вторых, это просто более краткий.

Ответ 11

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

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

И это где? падает для меня. Это полезно так редко и?: И if/else - такие быстрые и читаемые альтернативы, что на самом деле мало смысла использовать другой синтаксис, который не достигает ничего нового.

a = b?? c?? d?? е; звучит здорово. Но мне никогда не приходилось это делать!

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

name = (user == null)? "doe": user.Surname;

И, к сожалению,?? здесь не помогает.

Ответ 12

У меня была такая же проблема, как и у вас, но в пространстве использования LinqToXML тег не может быть в документе, поэтому использование ?? нецелесообразно для coallescing свойства этого тега.

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

Даже простой объект getter, например:

MyObject MyObj() { get { return _myObj ?? new MyObj(); } }

Вероятно, лучше обслуживается инициализатором...

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

Ответ 13

Я часто использую оператор с нулевым коалесцированием при разборе строк в других типах данных. У меня есть набор методов расширения, которые обертывают такие вещи, как Int32.TryParse, и возвращают nullable int вместо того, чтобы подвергать выходной параметр остальной части моего кода. Затем я могу проанализировать строку и указать значение по умолчанию, если синтаксический анализ не удался, в одной строке кода.

// ToNullableInt(), is an extension method on string that returns null
// if the input is null and returns null if Int32.TryParse fails.

int startPage = Request.QueryString["start"].ToNullableInt() ?? 0;