c# - 扩展 C# 合并运算符

标签 c# extension-methods

在我解释我想做什么之前,如果你看下面的代码,你会明白它应该做什么吗? (已更新 - 见下文)

Console.WriteLine(
  Coalesce.UntilNull(getSomeFoo(), f => f.Value) ?? "default value");

C# 已经有一个 null 合并运算符,它在简单对象上工作得很好,但如果您需要访问该对象的成员则无济于事。

例如

Console.WriteLine(getSomeString()??"default");

效果很好,但在这里对您没有帮助:

public class Foo
{
  public Foo(string value) { Value=value; }
  public string Value { get; private set; }
}

// this will obviously fail if null was returned
Console.WriteLine(getSomeFoo().Value??"default"); 

// this was the intention
Foo foo=getSomeFoo();
Console.WriteLine(foo!=null?foo.Value:"default");

因为这是我经常遇到的事情,所以我考虑使用扩展方法(旧版本):

public static class Extension
{
  public static TResult Coalesce<T, TResult>(this T obj, Func<T, TResult> func, TResult defaultValue)
  {
    if (obj!=null) return func(obj);
    else return defaultValue;
  }

  public static TResult Coalesce<T, TResult>(this T obj, Func<T, TResult> func, Func<TResult> defaultFunc)
  {
    if (obj!=null) return func(obj);
    else return defaultFunc();
  }
}

这让我可以写:

Console.WriteLine(getSomeFoo().Coalesce(f => f.Value, "default value"));

那么您认为这段代码可读吗? Coalesce 是个好名字吗?

编辑 1:按照 Marc 的建议删除括号

更新

我非常喜欢 lassevk 的建议和 Groo 的反馈。所以我添加了重载并没有将其作为扩展方法实现。我还认为 defaultValue 是多余的,因为您可以只使用现有的 ??运营商。

这是修改后的类:

public static class Coalesce
{
  public static TResult UntilNull<T, TResult>(T obj, Func<T, TResult> func) where TResult : class
  {
    if (obj!=null) return func(obj);
    else return null;
  }

  public static TResult UntilNull<T1, T2, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, TResult> func2) where TResult : class
  {
    if (obj!=null) return UntilNull(func1(obj), func2);
    else return null;
  }

  public static TResult UntilNull<T1, T2, T3, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, TResult> func3) where TResult : class
  {
    if (obj!=null) return UntilNull(func1(obj), func2, func3);
    else return null;
  }

  public static TResult UntilNull<T1, T2, T3, T4, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, T4> func3, Func<T4, TResult> func4) where TResult : class
  {
    if (obj!=null) return UntilNull(func1(obj), func2, func3, func4);
    else return null;
  }
}

示例用法:

Console.WriteLine(
  Coalesce.UntilNull(getSomeFoo(), f => f.Value) ?? "default value");

另一个例子:

public class Bar
{
  public Bar Child { get; set; }
  public Foo Foo { get; set; }
}

Bar bar=new Bar { Child=new Bar { Foo=new Foo("value") } };

// prints "value":
Console.WriteLine(
  Coalesce.UntilNull(bar, b => b.Child, b => b.Foo, f => f.Value) ?? "null");

// prints "null":
Console.WriteLine(
  Coalesce.UntilNull(bar, b => b.Foo, f => f.Value) ?? "null");

最佳答案

是的,我会理解的。是的,coalesce 是个好名字。是的,如果 C# 有像 Groovy 和其他一些语言那样的 null-safe 解引用运算符会更好:)

更新

C# 6 有这样一个运算符——空条件运算符,?。 例如:

var street = customer?.PrimaryAddress?.Street;

如果您仍需要默认值,请将它与原始的空合并运算符结合使用。例如:

var street = customer?.PrimaryAddress?.Street ?? "(no address given)";

或者,根据问题中的原始代码:

Console.WriteLine(getSomeFoo()?.Value ?? "default"); 

当然,请注意,只有当最终属性值可用但由于某种原因设置为 null 时可以使用该默认值时,以这种方式提供默认值才有效。

如果 x 的计算结果为 null,则表达式 x?.y 的结果为 null;否则它是 x.y 的结果。哦,您也可以将它用于条件方法调用:

possiblyNull?.SomeMethod();

关于c# - 扩展 C# 合并运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/665554/

相关文章:

c# - 从它们扩展的类中使用扩展方法

c# - 破解 MS Access 文件有多容易?如何保护它?

c# - Windows API 代码包 - ShellFile 不生成 PDF 位图

c# - 在上传发生之前确保上传文件的文件大小小于 maxRequestLength?

c# - 方法未显示在生产中的堆栈跟踪中

c# - LINQ .Cast() 扩展方法失败但(类型)对象有效

c# - "Enum as immutable rich-object": is this an anti-pattern?

c# - 从 WPF 中的任何/未指定的父容器断开元素

c# - 如何使用 DI usinq autofac .net 框架注册 ILogger(Microsoft.Extensions.Logging)

C# 扩展方法类型