?? Объединить для пустой строки?

Я все чаще и чаще проверяю строку на пустоту (например, "" или null) и условный оператор.

Текущий пример:

s.SiteNumber.IsNullOrEmpty() ? "No Number" : s.SiteNumber;

Это просто метод расширения, он эквивалентен:

string.IsNullOrEmpty(s.SiteNumber) ? "No Number" : s.SiteNumber;

Поскольку он пуст и не равен нулю, ?? не поможет. string.IsNullOrEmpty() версия ?? была бы идеальным решением. Я думаю, что должен быть более чистый способ сделать это (надеюсь!), Но я не мог его найти.

Кто-нибудь знает, как это сделать лучше, даже если это только в .Net 4.0?


person Nick Craver    schedule 10.03.2010    source источник
comment
Чтобы немного подразнить вас, вы можете легко определить специальные, специальные бинарные (и унарные, если на то пошло) операторы в F #. Вот let (|?) x y = if String.IsNullOrEmpty(x) then y else x и используйте его как s.SiteNumber |? "No Number".   -  person Stephen Swensen    schedule 01.04.2012


Ответы (10)


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

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

string result = s.SiteNumber.ConvertNullOrEmptyTo("No Number");
person Reed Copsey    schedule 10.03.2010
comment
Я думаю, что вы правы, и это самое чистое решение, доступное для чтения. Я бы хотел что-то вроде оператора ??? в C # 5, кто знает. - person Nick Craver; 11.03.2010
comment
а что бы ??? оператор делать? принимать значения по умолчанию в дополнение к нулям? звучит в лучшем случае чрезвычайно сложно - person bevacqua; 25.07.2011
comment
Может быть, с лямбда-выражениями? Например: предположим, что элемент допускает значение NULL, тогда ... item ?? x=> x.ToString() : null; - person Isaac Llopis; 06.03.2014
comment
@IsaacLlopis, который в конечном итоге выглядит грязнее, чем исходный фрагмент OP - person maksymiuk; 04.12.2015

C # уже позволяет нам заменять значения null на ??. Итак, все, что нам нужно, это расширение, которое преобразует пустую строку в null, а затем мы используем его следующим образом:

s.SiteNumber.NullIfEmpty() ?? "No Number";

Класс расширения:

public static class StringExtensions
{
    public static string NullIfEmpty(this string s)
    {
        return string.IsNullOrEmpty(s) ? null : s;
    }
    public static string NullIfWhiteSpace(this string s)
    {
        return string.IsNullOrWhiteSpace(s) ? null : s;
    }
}
person D'Arcy Rittich    schedule 10.03.2010
comment
Этот подход кажется более самодокументированным, поэтому за него проголосовали ... - person Allen; 20.11.2020

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

private static string Coalesce(params string[] strings)
{
    return strings.FirstOrDefault(s => !string.IsNullOrEmpty(s));
}

Использование:

string result = Coalesce(s.SiteNumber, s.AltSiteNumber, "No Number");

РЕДАКТИРОВАТЬ: Еще более компактный способ написания этой функции:

static string Coalesce(params string[] strings) => strings.FirstOrDefault(s => !string.IsNullOrEmpty(s));
person sfsr    schedule 09.07.2011
comment
Мне нравится, но пришлось исправить ошибку компилятора и сделать его немного компактнее. - person gregmac; 16.07.2014
comment
Почему вы называете это объединение, если оно не объединяет значения, а просто выбирает то, что не пусто? Имя сбивает с толку, чувак. - person Jimmyt1988; 10.01.2017
comment
Поскольку Coalesce - это термин, используемый многими базами данных для выполнения одной и той же операции (найти первое ненулевое значение). Объединение строк - это конкатенация. - person Cameron Forward; 29.01.2018
comment
Лучший ответ, если вы using System.Linq - person JoePC; 19.07.2019
comment
Это элегантная, хорошая работа. - person Mariano Luis Villa; 27.07.2019

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

public static string OrDefault(this string str, string @default = default(string))
{
    return string.IsNullOrEmpty(str) ? @default : str;
}

public static object OrDefault(this string str, object @default)
{
    return string.IsNullOrEmpty(str) ? @default : str;
}

Изменить: вдохновленный ответом sfsr, с этого момента я буду добавлять этот вариант в свой набор инструментов:

public static string Coalesce(this string str, params string[] strings)
{
    return (new[] {str})
        .Concat(strings)
        .FirstOrDefault(s => !string.IsNullOrEmpty(s));
}
person Justin Morgan    schedule 12.04.2012
comment
Я определенно использую термин Coalesce, так как он больше напоминает намерение оператора объединения null (??), хотя я изменил его на CoalesceTo. - person llaughlin; 01.06.2012
comment
Что делает префикс @ в параметре @default? Я такого раньше не видел. - person Drew Chapin; 14.12.2016
comment
@druciferre - это просто позволяет вам использовать default в качестве имени переменной, даже если это зарезервированное ключевое слово в C #. - person Justin Morgan; 28.12.2016
comment
Почему вы называете это объединение, если оно не объединяет значения, а просто выбирает то, что не пусто? Имя, чувак, сбивает с толку. - person Jimmyt1988; 10.01.2017
comment
@ Jimmyt1988 - потому что он приближается к стандартной функции T-SQL COALESCE. - person Justin Morgan; 10.01.2017
comment
@ Jimmyt1988 - Также потому, что он специально выбирает first непустую функцию в списке произвольной длины. Это тонкая деталь, но функция T-SQL работает точно так же. Название делает его интуитивно понятным для всех, кто знает эту функцию, с документацией или без нее. - person Justin Morgan; 10.01.2017

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

В итоге я получил:

public static string Coalesce(this string s, Func<string> func)
{
    return String.IsNullOrEmpty(s) ? func() : s;
}

Использование:

string navigationTitle = model?.NavigationTitle.
    Coalesce(() => RemoteTitleLookup(model?.ID)). // Expensive!
    Coalesce(() => model?.DisplayName);
person wensveen    schedule 23.06.2017

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

public static string Fallback(this string @this, string @default = "")
{
    return (@this == null || @this.Trim().Length == 0) ? @default : @this;
}
person Chilidog    schedule 11.10.2012
comment
Почему бы не использовать IsNullOrWhitespace вместо того, чтобы обрезать и длина его. - person weston; 19.12.2012
comment
code общедоступная статическая строка Coalesce (эта строка @this, string @default =) {return (@this == null || String.IsNullOrWhiteSpace (@this))? @ по умолчанию: @ это; } - person paul-2011; 23.01.2016

Я просто использую метод расширения NullIfEmpty, который всегда будет возвращать значение null, если строка пуста, что позволяет ?? (Null Coalescing Operator) будет использоваться как обычно.

public static string NullIfEmpty(this string s)
{
    return string.IsNullOrEmpty(s) ? null : s;
}

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

string string1 = string2.NullIfEmpty() ?? string3.NullIfEmpty() ?? string4;
person jjr2000    schedule 22.02.2018

как насчет метода расширения строки ValueOrDefault ()

public static string ValueOrDefault(this string s, string sDefault)
{
    if (string.IsNullOrEmpty(s))
        return sDefault;
    return s;
}

или вернуть null, если строка пуста:

public static string Value(this string s)
{
    if (string.IsNullOrEmpty(s))
        return null;
    return s;
}

Однако не пробовал эти решения.

person devio    schedule 10.03.2010
comment
Мне нравится вариант №1, хотя я бы назвал его более семантическим, например Or (), поэтому я мог бы написать строку s = s.SiteNumber.Or (по умолчанию); - person jvenema; 29.04.2011
comment
Вызов чего-то ...OrDefault() мог бы сбить с толку, если бы он не вел себя как остальные ...OrDefault() методы фреймворка. Нравится вам это или нет, но MS придала особое значение тому, что именование и отклонение от этого поведения в пользовательских методах излишне сбивает с толку пользователей вашего API. - person mattmc3; 10.07.2011

Я использую собственный метод расширения String Coalesce. Поскольку те, кто здесь использует LINQ, тратят впустую ресурсы на трудоемкие операции (я использую его в жестких циклах), я поделюсь своим:

public static class StringCoalesceExtension
{
    public static string Coalesce(this string s1, string s2)
    {
        return string.IsNullOrWhiteSpace(s1) ? s2 : s1;
    }
}

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

string s1 = null;
string s2 = "";
string s3 = "loudenvier";
string s = s1.Coalesce(s2.Coalesce(s3));
Assert.AreEqual("loudenvier", s);

Я часто им пользуюсь. Одна из тех "служебных" функций, без которых вы не сможете жить после первого использования :-)

person Loudenvier    schedule 17.01.2013
comment
Я не думаю, что вы понимаете, почему они используют LINQ, и поскольку параметры оцениваются перед вызовами, ваш s2.Coalesce(s3) запускается даже тогда, когда он не нужен. Лучше использовать расширение NullIfEmpty() и ??. - person NetMage; 16.04.2020
comment
@NetMage Я могу гарантировать вам, что версии LINQ намного менее производительны, чем та, которую я представил. Вы можете создать простой тест, чтобы проверить это, если хотите. Я предлагаю использовать github.com/dotnet/BenchmarkDotNet, чтобы избежать распространенных ошибок при написании кода тестирования. - person Loudenvier; 21.04.2020

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

#region QQ

[DebuggerStepThrough]
public static string QQQ(this string str, string value2)
{
    return (str != null && str.Length > 0)
        ? str
        : value2;
}

[DebuggerStepThrough]
public static string QQQ(this string str, string value2, string value3)
{
    return (str != null && str.Length > 0)
        ? str
        : (value2 != null && value2.Length > 0)
            ? value2
            : value3;
}


// Following is only two QQ, just checks null, but allows more than 1 string unlike ?? can do:

[DebuggerStepThrough]
public static string QQ(this string str, string value2, string value3)
{
    return (str != null)
        ? str
        : (value2 != null)
            ? value2
            : value3;
}

#endregion
person Nicholas Petersen    schedule 28.01.2014
comment
Если вам нравятся короткие имена, вы можете называть его Or, и я бы использовал ключевое слово params, как и другие ответы, что позволяет избежать дублирования определений для нескольких параметров. - person Chiel ten Brinke; 11.07.2019
comment
Спасибо за идею. Я давно заменил это имя на FirstNotNull в своем собственном использовании. На params было бы лучше не делать этого для сценария по умолчанию или двух, поскольку params вызывает ненужное выделение массива, когда у вас есть только один или два входа по умолчанию. После этого имеет смысл. - person Nicholas Petersen; 11.07.2019