扩展C#合并运营 [英] Extending the C# Coalesce Operator

查看:108
本文介绍了扩展C#合并运营的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我解释一下我想做的事,如果你看看下面的代码,你会明白什么是应该做的?的(更新 - 见下文)



  Console.WriteLine(
Coalesce.UntilNull(getSomeFoo (),F => f.Value) - 默认值);



C#已经有一个空合并运算符的作品相当不错的简单对象,但并没有帮助,如果你需要访问该对象的成员。



例如:

  Console.WriteLine(getSomeString()??默认); 

工作得很好,但它不会帮助你在这里:

 公共类Foo 
{
公共美孚(字符串值){值=价值; }
公共字符串值{获得;私人集; }
}

//如果返回null,则此显然会失败
Console.WriteLine(getSomeFoo()值??默认。);

//这是有意
富富= getSomeFoo();
Console.WriteLine(!?富=空foo.Value:默认);



由于这一点是我遇到很多时候我想过使用的扩展方法的(旧版本)的:

 公共静态类扩展
{
公共静态TResult凝聚< T,TResult>(这件T OBJ,Func键< T,TResult> FUNC,TResult设置defaultValue)
{
如果(OBJ!= NULL)返回FUNC(OBJ);
,否则返回设置defaultValue;
}

公共静态TResult凝聚< T,TResult>(这件T OBJ,Func键< T,TResult> FUNC,Func键< TResult> defaultFunc)
{
如果(!OBJ = NULL)返回FUNC(OBJ);
否则返回defaultFunc();
}
}



这让我写:

  Console.WriteLine(getSomeFoo()COALESCE(F =方式> f.Value,默认值)); 



所以,你会认为这个代码是可读的? ?是凝聚一个好听的名字



编辑1:去掉括号由马克的建议



更新



我真的很喜欢lassevk的建议和Groo的反馈。所以我加了过载和没有实现它作为一个扩展的方法。我还决定,设置defaultValue是多余的,因为你可以只使用现有的? 。运营商为



这是修改后的类:

 公开静态类合并
{
公共静态TResult UntilNull< T,TResult>(T OBJ,Func键< T,TResult> FUNC),其中TResult:类
{
如果(OBJ! = NULL)返回FUNC(OBJ);
,否则返回NULL;
}

公共静态TResult UntilNull&下; T1,T2,TResult>(T1物镜,Func键与所述的T1,T2和GT; func1的,Func键与下; T2,TResult> FUNC2)其中TResult:类
{
如果(!OBJ = NULL)返回UntilNull(func1的(OBJ),FUNC2);
,否则返回NULL;
}

公共静态TResult UntilNull&下; T1,T2,T3,TResult>(T1物镜,Func键与所述的T1,T2和GT; func1的,Func键与下; T2,T3> FUNC2,Func键与下; T3, TResult> FUNC3)其中TResult:类
{
如果(!OBJ = NULL)返回UntilNull(func1的(OBJ),FUNC2,FUNC3);
,否则返回NULL;
}

公共静态TResult UntilNull&下; T1,T2,T3,T4,TResult>(T1物镜,Func键与所述的T1,T2和GT; func1的,Func键与下; T2,T3> FUNC2,Func键&下; T3,T4> FUNC3,Func键< T4,TResult> FUNC4)其中TResult:类
{
如果(!OBJ = NULL)返回UntilNull(func1的(OBJ),FUNC2,FUNC3,FUNC4);
,否则返回NULL;
}
}



使用范例:

  Console.WriteLine(
Coalesce.UntilNull(getSomeFoo(),F => f.Value) - 默认值);



另外一个例子:

 公共类酒吧
{
公共酒吧儿童{搞定;组; }
公共富富{搞定;组; }
}

吧吧=新的酒吧{儿童=新的​​酒吧{美孚=新的Foo(值)}};

//输出值:
Console.WriteLine(
Coalesce.UntilNull(巴,B => b.Child,B => b.Foo,女= GT; f.Value) - 空);

//输出空:
Console.WriteLine(
Coalesce.UntilNull(巴,B => b.Foo,F => f.Value)? ? 空值);


解决方案

六年后和的 空,条件运算符 的位置:




有时代码往往淹没在空检查了一下。在
空条件运算符可以访问成员和元素只有
当接收器是不是空的,否则提供一个空的结果:

 诠释?长度=客户。长度?; //空,如果客户是空的客户
第一=客户[0]; //空,如果客户是空



空条件操作便利,连同$ B $使用b空合并运算符??:?

  INT长度=客户。长度? 0; // 0,如果客户是空



空条件运算符具有短路行为,
,其中紧随其后的成员链访问,元素
访问,如果原来的
接收器是不是空的调用才会执行:

 诠释?第一=客户[0] .Orders.Count()?; 

这例子基本上等同于:

 诠释?首先=(顾客!= NULL)?客户[0] .Orders.Count():空; 



除了客户只计算一次。会员
没有访问,访问的元素和调用紧随?
的,除非客户执行有一个非空值。



当然空有条件运营商可以自行链接,在
情况下,有一个需要在链检查空不止一次:

 诠释?第一=客户[0] .Orders .Count之间的()?; 



注意,调用(带括号的参数列表)不能
紧跟在?操作员 - 这将导致太多
句法歧义。因此,调用
委托,只有当它的存在不能正常工作的简单方法。但是,您可以通过
上的委托Invoke方法做到这一点:

 如果(谓词.Invoke(E )??假){...} 

我们期待这种模式的一个非常普遍的使用将是
触发事件:

 的PropertyChanged .Invoke(这一点,参数); 

这是你之前检查null
触发了一个方便,线程安全的方式事件。它的线程安全的原因是,该功能
评估左侧只有一次,并保持它在一个临时
变量



Before I explain what I want to do, if you look at the following code, would you understand what it's supposed to do? (updated - see below)

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

C# already has a null-coalescing operator that works quite well on simple objects but doesn't help if you need to access a member of that object.

E.g.

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

works very well but it won't help you here:

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

Since this is something that I come across quite often I thought about using an extension method (old version):

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

Which allows me to write:

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

So would you consider this code to be readable? Is Coalesce a good name?

Edit 1: removed the brackets as suggested by Marc

Update

I really liked lassevk's suggestions and Groo's feedback. So I added overloads and didn't implement it as an extension method. I also decided that defaultValue was redundant because you could just use the existing ?? operator for that.

This is the revised class:

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

Sample usage:

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

Another sample:

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

解决方案

Six years later and Null-conditional operators are here:

Sometimes code tends to drown a bit in null-checking. The null-conditional operator lets you access members and elements only when the receiver is not-null, providing a null result otherwise:

int? length = customers?.Length; // null if customers is null Customer
first = customers?[0];  // null if customers is null

The null-conditional operator is conveniently used together with the null coalescing operator ??:

int length = customers?.Length ?? 0; // 0 if customers is null

The null-conditional operator exhibits short-circuiting behavior, where an immediately following chain of member accesses, element accesses and invocations will only be executed if the original receiver was not null:

int? first = customers?[0].Orders.Count();

This example is essentially equivalent to:

int? first = (customers != null) ? customers[0].Orders.Count() : null;

Except that customers is only evaluated once. None of the member accesses, element accesses and invocations immediately following the ? are executed unless customers has a non-null value.

Of course null-conditional operators can themselves be chained, in case there is a need to check for null more than once in a chain:

int? first = customers?[0].Orders?.Count();

Note that an invocation (a parenthesized argument list) cannot immediately follow the ? operator – that would lead to too many syntactic ambiguities. Thus, the straightforward way of calling a delegate only if it’s there does not work. However, you can do it via the Invoke method on the delegate:

if (predicate?.Invoke(e) ?? false) { … }

We expect that a very common use of this pattern will be for triggering events:

PropertyChanged?.Invoke(this, args);

This is an easy and thread-safe way to check for null before you trigger an event. The reason it’s thread-safe is that the feature evaluates the left-hand side only once, and keeps it in a temporary variable.

这篇关于扩展C#合并运营的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆