【问题标题】:Negate the null-coalescing operator否定空合并运算符
【发布时间】:2011-02-20 15:01:10
【问题描述】:

我有一堆需要使用 .Trim() 的字符串,但它们可以为空。如果我能做这样的事情会更简洁:

string endString = startString !?? startString.Trim();

如果左边的部分不为空,则基本上返回右边的部分,否则只返回空值。我刚刚结束了使用三元运算符,但有没有为此目的使用 null-coalescing 运算符?

【问题讨论】:

  • 我不这么认为,tbh !string.IsNullOrEmpty(startString) ? startString.Trim() : null; 有什么问题
  • 据我了解您的问题,您希望传播 null,即如果字符串为 null,则返回 null。否则,重新调整修剪后的字符串。那是对的吗?如果是这种情况,则没有内置的运算符或方法可以这样做。您可以使用三元运算符(如您所做的那样)或编写方法。
  • 我还在等待这个运算符成为语言的一部分:(
  • 我喜欢 @sixlettervariables 方法,即使 startString 为空,我们也需要返回 empty string
  • 听起来你真正追求的是?. : 三元运算符;如果左侧操作数不为空,则访问相应的成员,否则计算右侧。示例用法:theValue = someThing?.SomeProperty : defaultValue; 这将是一个有用的运算符,但它的语法和绑定将完全不同于该语言中的任何其他内容。

标签: c# null-coalescing-operator


【解决方案1】:

您可以创建一个扩展方法,当它尝试修剪值时返回 null

public String TrimIfNotNull(this string item)
{
   if(String.IsNullOrEmpty(item))
     return item;
   else
    return item.Trim();
}

请注意,您不能将其命名为 Trim,因为扩展方法不能覆盖实例方法。

【讨论】:

  • item 为空时,这感觉很糟糕......但是,我确实确认它有效。 string s = null; s.TrimIfNotNull(); 没有 NullReferenceException 就像您使用常规实例方法(即使是不引用任何成员的方法)一样。
  • 它的工作原理非常合理。扩展方法只不过是附加到对象的静态方法。他们真的没有理由不工作。该类不能依赖于它们所做的任何事情,因为它们不是在原始类创建时创建的,并且它们无法访问任何私有方法或对象。不允许在空对象上使用 会很困难(尽管我承认一开始有点奇怪)。
  • 是的,该功能的高潮是IfNotNull扩展方法:public V IfNotNull<T, V>(this T @in, Func<T,V> access)
【解决方案2】:

不规范:不是我喜欢,但你可以使用:

string endString = (startString ?? String.Empty).Trim();

按照规范,最好是像@Kevin's 这样的扩展方法:

string endString = (startString == null ? null : startString.Trim());

【讨论】:

  • 不按照他的要求传播 null
  • 如果 startString 为空,则不返回空。
  • 我读了第二遍才意识到他实际上想要空值......@Kevin 在这种情况下有正确的想法。
  • 为什么不使用string.IsNullOrEmpty()
  • 我收集到,他希望 null 保持为空,而为空保持空。
【解决方案3】:
string endString = string.IsNullOrEmpty(startString) ? startString : startString.Trim();

虽然我还编写了一个名为“safeTrim”的字符串扩展方法,它可以在一种方法中完成您所描述的操作,而不必每次都使用这个方法。查看Kevin's respone 获取代码。

编辑:哇,我有各种各样的倒退,错误命名的变量和反转的三元运算符,更有理由编写一个扩展方法和代码检查它比我做得更好!

【讨论】:

  • Ninja 编辑感谢 Frank 的评论提醒我这是 string.IsNullOrEmpty(foo) 而不是 foo.IsNullOrEmpty()
  • 检查是否为空。不是他想要的
  • endString 在此特定语句中定义时,它怎么可能已经在范围内?我认为你需要做更多的忍者编辑......
  • 我想你的意思是string endString = string.IsNullOrEmpty(startString) ? startString : startString.Trim();。如果它是 null/empty,他想要 null 字符串,如果它是 not null/empty,他想要修剪它。
  • @Sarah 确实我做到了,我把它倒退了很多,甚至为一个分支选择了错误的变量名,哇 headdesk
【解决方案4】:

从 C# 6.0(.NET Framework 4.6 / Visual Studio 2015)开始,您可以使用null-conditional member access

 string? endString = startString?.Trim();

【讨论】:

  • 应该是?而不是 .?
【解决方案5】:

抱歉,我遇到了同样的问题,我使用 lambda 操作解决了这个问题。它不是最漂亮的,但它使我的代码简洁。

很遗憾 C# 不支持静态导入或单个函数导入,但无论如何:

在某处定义这个函数:

private static TResult N<TParent,TResult>(TParent parent, Func<TParent,TResult> operation) {
    if( parent == null ) return default(TResult);
    return operation( parent );
}

然后在您的示例中使用它:

String endString = N(startString, s => s.Trim());

如果第一个参数为空,N 函数返回null,否则它将以值作为参数计算指定的 lambda 函数。

当然,您可以像这样嵌套它。例如,为了安全地解除对长链的引用,例如

String someValue = someObject.SomeProperty.SomeOtherProperty.SomeMethod().SomeFinalProperty;

如果这些属性或方法中的任何一个返回 null,那么您必须在任何地方插入 null 检查,或者您可以这样做:

String someValue = N(N(N(N(someObject, o => o.SomeProperty), o => o.SomeOtherProperty), o => o.SomeMethod()), o => o.SomeFinalProperty);

正如我所说,它不是最漂亮的:)

您可以通过使N 成为System.Object 的扩展方法来简化此操作,如下所示:

String someValue = someObject.N( o => o.SomeProperty ).N( o => o.SomeOtherProperty ).N( o => o.SomeMethod() ).N( o => o.SomeFinalProperty );

...我认为它更整洁。

【讨论】:

  • 受类约束的泛型似乎比System.Object 更好,我认为最好有一些接受各种数量的“额外”参数的变体。必须捕获任何内容(包括 this)的 lambda 与不需要捕获任何内容的 lambda 之间的性能可能存在巨大差异,因此允许显式传递参数而不是捕获参数可能是一个巨大的胜利。
【解决方案6】:

使用

string endString = (startString ?? "").Trim();

如果 startString 为空,则使用 empy 字符串。但是,当endString 为 null 时,这不会返回 null。

快进到 2021 年:
10 年后startString?.Trim() 绝对是更好的选择。这确实返回null

【讨论】:

  • 如果 startString 为空,他希望 endString 为空。您的示例将返回 string.Empty
【解决方案7】:

以下不传播 null 但它接受 null 作为参数并在这种情况下返回一个空字符串。

using Microsoft.VisualBasic;  // you need to add a reference to Microsoft.VisualBasic.dll

    ...
    string endString = Strings.Trim(startString);
    ...

duck&run...

【讨论】:

    【解决方案8】:

    作为旁注,如果您使用的是 .NET 4,则可以使用一种新的便捷方法 String.IsNullOrWhiteSpace

    【讨论】:

    • 有趣的方法,但似乎与 OP 的问题正交。
    猜你喜欢
    • 2012-09-19
    • 2011-06-19
    • 2013-09-13
    • 2010-10-03
    • 2017-04-08
    • 2015-03-27
    • 2023-03-23
    • 2012-09-23
    • 1970-01-01
    相关资源
    最近更新 更多