?? 合并为空字符串?


165

我发现自己做的越来越多的事情是检查字符串是否为空(如in ""或null)和条件运算符。

当前示例:

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

这只是一个扩展方法,它等效于:

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

由于它是空的而不是null,??因此不会解决问题。一个string.IsNullOrEmpty()版本的??将是完美的解决方案。我在想必须有一种更清洁的方法(我希望!),但是我一直茫然地找不到它。

有谁知道这样做的更好方法,即使仅在.Net 4.0中也是如此?


11
只是为了吸引您,您可以轻松地在F#中定义自定义的即席二进制(就此而言,也是一元)运算符。在这里let (|?) x y = if String.IsNullOrEmpty(x) then y else x使用就好s.SiteNumber |? "No Number"
Stephen Swensen 2012年

Answers:


72

没有内置的方法可以做到这一点。您可以使扩展方法返回字符串或null,但这将使合并运算符起作用。但是,这很奇怪,我个人更喜欢您当前的方法。

由于您已经在使用扩展方法,为什么不制作一个返回值或默认值的方法:

string result = s.SiteNumber.ConvertNullOrEmptyTo("No Number");

7
我认为您是对的,这是目前可用的最干净的解决方案,并且仍然可读。我很喜欢???C#5中的运算符,但我知道。
尼克·克拉弗

2
以及什么?接线员呢?除空值外还采用默认值?听起来充其量是极其复杂的
bevacqua 2011年

1
用lambda表达式也许?例如:假设“ item”为空,则... item ?? x=> x.ToString() : null;
Isaac Llopis 2014年

@IsaacLlopis这最终看起来凌乱儿比OP的原始片段
maksymiuk

133

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;
    }
}

44

我知道这是一个古老的问题-但我一直在寻找答案,以上都不适合我的需求以及最终使用的东西:

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));

1
我喜欢,但必须修复编译器错误并使它更紧凑。
gregmac

当它不将值组合在一起而只选择一个不为空的值时,为什么将其称为“合并”?这是一个令人困惑的名字家伙。
Jimmyt1988 '17

8
因为Coalesce是许多数据库用来执行相同操作的术语(查找第一个非空值)。将字符串连接在一起就是串联。
卡梅伦前进

如果您是最佳答案using System.Linq
JoePC '19

很好,很好。
马里亚诺·路易斯

16

我有几个我喜欢使用的实用程序扩展:

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));
}

1
我肯定使用了“ Coalesce”一词,因为它更类似于空合并运算符(??)的意图,尽管我将其更改为“ CoalesceTo”。
llaughlin

参数上的@前缀有什么作用@default?我以前从未见过。
德鲁·查平

3
@druciferre- default即使它是C#中的保留关键字,也只允许您用作变量名。
贾斯汀·摩根

1
@ Jimmyt1988-因为它近似于标准的T-SQL COALESCE函数。
贾斯汀·摩根

1
@ Jimmyt1988-也是因为它专门选择了任意长度列表中的第一个非空函数。这是一个细微的细节,但是T-SQL函数的工作方式相同。该名称使知道该功能的任何人(无论有没有文档)都可以直观地看到它。
贾斯汀·摩根

6

一种比之前提出的方法更快的扩展方法:

public static string Fallback(this string @this, string @default = "")
{
    return (@this == null || @this.Trim().Length == 0) ? @default : @this;
}

11
为什么不使用IsNullOrWhitespace而不是修剪和加长它。
weston 2012年

1
code公共静态字符串Coalesce(此字符串@this,字符串@default =“”){return(@this == null || String.IsNullOrWhiteSpace(@this))吗?@default:@this; }
paul-2011

6

空合并运算符的优点之一是它会短路。当第一部分不为空时,不评估第二部分。当后备需要昂贵的操作时,这很有用。

我最终得到了:

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);

6

我只是使用了一个NullIfEmpty扩展方法,如果字符串为空,它将始终返回null?(空合并运算符)照常使用。

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

然后,这允许?? 可以正常使用,并使链接易于阅读。

string string1 = string2.NullIfEmpty() ?? string3.NullIfEmpty() ?? string4;

3

字符串扩展方法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;
}

虽然没有尝试这些解决方案。


2
我喜欢那里的选项#1,尽管我将其称为Or()之类的语义,但是我可以写成“ string s = s.SiteNumber.Or(“ Default”);“
jvenema 2011年

2
...OrDefault()如果某些东西的行为不像其他框架...OrDefault()方法那样,那将造成混乱。不管您喜欢与不喜欢,MS都赋予了特定的含义,即自定义方法中的命名和行为会不必要地使您的API用户感到困惑。
mattmc3 2011年

3

我正在使用自己的字符串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);

我经常使用。您必须先使用这些“实用”功能,然后才能使用它:-)


我认为您不理解他们为什么使用LINQ,并且由于参数是在调用之前进行评估的,s2.Coalesce(s3)因此即使在不需要时也会运行您的代码。最好使用NullIfEmpty()扩展名和??
NetMage

@NetMage我可以向您保证LINQ版本的性能要比我介绍的版本低很多。您可以根据需要创建一个简单的基准测试。我建议在编写基准测试代码时使用github.com/dotnet/BenchmarkDotNet来防止常见的陷阱。
Loudenvier

0

我当然喜欢以下扩展方法的简洁性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

如果您喜欢短名称,则可以将其称为Or,和params其他答案一样,我将使用该关键字,这样可以避免多个参数的重复定义。
Chiel 10 Brinke

谢谢你的主意。我很早就用自己的名字将此名称替换为“ FirstNotNull”。在上params,最好不要对一两个默认方案执行此操作,因为params当您只有一个或两个默认输入时,会不必要地分配数组。在那之后是有道理的。
尼古拉斯·彼得森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.