【问题标题】:C# if-null-then-null expressionC# if-null-then-null 表达式
【发布时间】:2011-05-13 18:05:55
【问题描述】:

只是为了好奇/方便:C# 提供了两个我知道的很酷的条件表达式功能:

string trimmed = (input == null) ? null : input.Trim();

string trimmed = (input ?? "").Trim();

对于我经常遇到的情况,我想念另一个这样的表达方式:

如果输入引用为空,则输出应为空。否则,输出应该是访问输入对象的方法或属性的结果。

我在第一个示例中就是这样做的,但 (input == null) ? null : input.Trim() 非常冗长且难以阅读。

这种情况还有其他条件表达式吗,或者我可以优雅地使用?? 运算符吗?

【问题讨论】:

  • 正如 Jon 下面提到的,我们现在可以在 c# 6.0 中使用空条件运算符,例如 theText?.Trim()

标签: c# .net conditional-operator conditional-expressions


【解决方案1】:

类似于 Groovy 的 null 安全解引用运算符?

string zipCode = customer?.Address?.ZipCode;

我推测 C# 团队已经查看了这一点,发现它并不像人们想象的那样简单优雅地设计……虽然我还没有听说过问题的细节。

我不相信目前语言中有任何这样的事情,恐怕......我还没有听说过任何计划,尽管这并不是说它不会在某些时候发生点。

编辑:它现在将成为 C# 6 的一部分,作为“空条件运算符”。

【讨论】:

  • 我希望有一天我们在 C# 中有这样的空安全解引用运算符。
  • Danny:如果您接受同时失去打字安全性和速度,您已经可以使用动态来玩它了。还有优雅的“?”语法必须由扩展方法调用替换。该方法可以命名为 AndAnd() 来镜像andand.rubyforge.org
  • 看来 C# 团队可能要借用那个运算符了。 channel9.msdn.com/Forums/Coffeehouse/…
  • @JonasElfström:万岁。不幸的是,我无法让 Mads 发言——我真的很想看到这个……
【解决方案2】:

作为一种解决方法,您可以使用基于 Maybe monad 的方法。

public static Tout IfNotNull<Tin, Tout>(this Tin instance, Func<Tin, Tout> Output)
{
    if (instance == null)
        return default(Tout);
    else
        return Output(instance);
}

这样使用:

int result = objectInstance.IfNotNull(r => 5);
var result = objectInstance.IfNotNull(r => r.DoSomething());

【讨论】:

  • 这真的很棒 - 如果您正在访问引用的实体,我将它与实体框架一起使用,例如var x=Entity1.Entity2.IfNotNull(x=&gt;x.EntityDescription) ?? string.Empty 返回包含在 Entity1 引用的 Entity2 中的 EntityDescription - 如果任何对象 Entity1 或 Entity2 为空,则返回一个空字符串。如果没有 IfNotNull,你会得到一个又长又丑的表达式。干得好!
【解决方案3】:

您可以选择自定义Nullify 类或NullSafe 扩展方法,如下所述:http://qualityofdata.com/2011/01/27/nullsafe-dereference-operator-in-c/

用法如下:

//Groovy:
bossName = Employee?.Supervisor?.Manager?.Boss?.Name

//C# Option 1:
bossName = Nullify.Get(Employee, e => e.Supervisor, s => s.Manager,
                       m => m.Boss, b => b.Name);
//C# Option 2:
bossName = Employee.NullSafe( e => e.Supervisor ).NullSafe( s => s.Boss )
                      .NullSafe( b => b.Name );

【讨论】:

  • NullSafe 扩展方法太棒了!
【解决方案4】:

没有任何内置功能,但如果需要,您可以将其全部封装在扩展方法中(尽管我可能不会打扰)。

对于这个具体的例子:

string trimmed = input.NullSafeTrim();

// ...

public static class StringExtensions
{
    public static string NullSafeTrim(this string source)
    {
        if (source == null)
            return source;    // or return an empty string if you prefer

        return source.Trim();
    }
}

或者更通用的版本:

string trimmed = input.IfNotNull(s => s.Trim());

// ...

public static class YourExtensions
{
    public static TResult IfNotNull<TSource, TResult>(
        this TSource source, Func<TSource, TResult> func)
    {
        if (func == null)
            throw new ArgumentNullException("func");

        if (source == null)
            return source;

        return func(source);
    }
}

【讨论】:

  • +1 表示NullSafeTrimIfNotNull 不能说服我,我看不到可读性的提升,只有代码复杂性的提升。
  • @chiccodoro:我不相信这两种方法都可以解决这个特殊的“问题”,我只是想我会把它们混在一起!对于这种情况,我可能几乎每次都使用if (foo != null) foo = foo.Trim();,尽管在许多其他情况下使用表达式而不是语句很方便和/或有必要。
【解决方案5】:

我有同样的问题,我写了几个小扩展方法:

public static TResult WhenNotNull<T, TResult>(
    this T subject, 
    Func<T, TResult> expression)
    where T : class
{
    if (subject == null) return default(TResult);
    return expression(subject);
}

public static TResult WhenNotNull<T, TResult>(
    this T subject, Func<T, TResult> expression,
    TResult defaultValue)
    where T : class
{
    if (subject == null) return defaultValue;
    return expression(subject);
}

public static void WhenNotNull<T>(this T subject, Action<T> expression)
    where T : class
{
    if (subject != null)
    {
        expression(subject);
    }
}

你这样使用它;

string str = null;
return str.WhenNotNull(x => x.Length);

IEnumerable<object> list;
return list.FirstOrDefault().WhenNotNull(x => x.id, -1);

object obj;
IOptionalStuff optional = obj as IOptionalStuff;
optional.WhenNotNull(x => x.Do());

还有可空类型的重载。

【讨论】:

  • 看起来很有趣,但我不确定你真正从中获得了什么。在我看来,它的可读性并不高,而且在技术上会在编译后的代码中引入更多的复杂性。
  • @chiccodoro:在某些情况下它更具可读性,例如在 FirstOrDefault 之后或在类似情况下,您不需要另一个变量并且没有 if。您可以在不使用大量变量的情况下链接它们。这还取决于您是允许将 if 写成一行,还是强制开发人员将其写成四行。
【解决方案6】:

目前我们只能写一个扩展方法,如果你不想重复自己,恐怕。

public static string NullableTrim(this string s)
{
   return s == null ? null : s.Trim();
}

【讨论】:

    猜你喜欢
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 2018-05-29
    • 1970-01-01
    • 2014-10-29
    • 1970-01-01
    相关资源
    最近更新 更多