58

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

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

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

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

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

在我的第一个示例中,我已经完全做到了这一点,但是(input == null) ? null : input.Trim()非常冗长且难以阅读。

这种情况下是否有另一个条件表达式,或者我可以??优雅地使用运算符?

4

6 回答 6

50

像 Groovy 的 null 安全解除引用运算符之类的东西?

string zipCode = customer?.Address?.ZipCode;

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

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

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

于 2010-11-22T10:07:53.673 回答
10

您可以选择自定义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 );
于 2011-01-31T05:38:29.753 回答
9

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

public static string NullableTrim(this string s)
{
   return s == null ? null : s.Trim();
}
于 2010-11-22T10:12:09.713 回答
8

作为一种解决方法,您可以使用基于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());
于 2010-11-22T10:45:41.453 回答
6

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

对于这个具体的例子:

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);
    }
}
于 2010-11-22T10:12:53.457 回答
4

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

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

可空类型也有重载。

于 2010-11-22T10:19:19.100 回答