C# 用 空合并运算符??: int length = customers?.Length ?? 0; // 0 if customers is null
空条件运算符显示短路行为, 当紧接其后的成员链访问时,元素 只有在原始 接收方不为空:C# 用 空合并运算符??: int length = customers?.Length ?? 0; // 0 if customers is null,c#,extension-methods,C#,Extension Methods,空条件运算符显示短路行为, 当紧接其后的成员链访问时,元素 只有在原始 接收方不为空: int? first = customers?[0].Orders.Count(); 该示例实质上等同于: int? first = (customers != null) ? customers[0].Orders.Count() : null; 除了只对客户进行一次评估。没有成员 访问、元素访问和调用紧随其后? 除非客户具有非空值,否则将执行 当然,空条件运算符本身也可以链接,例如 如果需要在链中多次
int? first = customers?[0].Orders.Count();
该示例实质上等同于:
int? first = (customers != null) ? customers[0].Orders.Count() : null;
除了只对客户进行一次评估。没有成员
访问、元素访问和调用紧随其后?
除非客户具有非空值,否则将执行
当然,空条件运算符本身也可以链接,例如
如果需要在链中多次检查null:
int? first = customers?[0].Orders?.Count();
请注意,调用(带括号的参数列表)不能
立即跟进?操作员–这将导致太多
句法歧义。因此,调用
只有在不起作用的情况下才授权。但是,您可以通过
委托上的Invoke方法:
if (predicate?.Invoke(e) ?? false) { … }
我们希望这种模式的一个非常常见的用途是
触发事件:
PropertyChanged?.Invoke(this, args);
这是一种简单且线程安全的方法,可以在使用前检查null
触发事件。它是线程安全的原因是
仅对左侧求值一次,并将其保留在临时位置
变数
不过,这会强制实现不变性(至少是冰棒不变性),并且不能很好地处理“default(t)”等问题。此外,它更普遍地假设您确实控制了所讨论的类型(情况并非总是如此);在某些情况下,只有“in-line if”才能起作用,例如在为LINQ to(某些数据库)构建lambda时,“in-line if”指的是?:操作符?对不起,我指的是一个noraml“if”语句,它没有隐藏在单独的方法中。谢谢-删除了括号。我认为SafeSelect会建议一个枚举,但它不是。。。关于取消引用,我不确定。。。最难的部分总是命名:)我必须同意Marc,你的扩展方法不像??代码示例中的运算符。哇!我知道ext.方法基本上是“thiscall”静态方法,但我仍然认为它们在对Null实例调用时会抛出Null引用异常(因为非虚拟实例方法实际上以相同的方式工作)。。。我想这种方式更有意义。谢谢你的评论!这正是我想要的——或者说不是想要的;)API应该遵循“最小惊喜原则”——所以我想使用扩展方法不是一个好主意——我会重新考虑我的设计!查看我的更新-C#6很可能有你想要的:)谢谢,已经在这里绊倒了;)他需要lambdas,因为
something\u other
是something
的属性。将属性解引用封装在lambda中允许他延迟评估它,直到他知道这样做是安全的。这样做是错误的方法,因为您将该知识推给了原始方,而原始方应该是黑盒。如果您想要lazy-eval,只需使用lazy-eval类包装您的属性,并将这样的混合传递给方法(在这里合并)。否则你会以coalesce,coalesce\u lazy,等等结束。
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");
var street = customer?.PrimaryAddress?.Street;
var street = customer?.PrimaryAddress?.Street ?? "(no address given)";
Console.WriteLine(getSomeFoo()?.Value ?? "default");
possiblyNull?.SomeMethod();
f => f.Value
public class Foo
{
public Foo(string value) { Value=value; }
public string Value { get; private set; }
private static Foo nullFoo = new Foo("default value");
public static Foo NullFoo { get { return nullFoo; } }
}
public class NullFoo : Foo
{
private NullFoo() : base("default value") { }
private static NullFoo instance = new NullFoo();
public static Foo Instance { get { return instance; } }
}
Console.WriteLine((getSomeFoo() ?? NullFoo.Instance).Value);
public static TResult Coalesce<T, TResult>(this T obj, Func<T, TResult> func, TResult defaultValue)
{
if (obj == null)
return defaultValue;
return func(obj);
}
public static TResult Coalesce<T1, T2, TResult>(this T1 obj, Func<T1, T2> func1, Func<T2, TResult> func2, TResult defaultValue)
{
if (obj == null)
return defaultValue;
T2 obj2 = func1(obj);
if (obj2 == null)
return defaultValue;
return func2(obj2);
}
public static TResult Coalesce<T1, T2, T3, TResult>(this T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, TResult> func3, TResult defaultValue)
{
if (obj == null)
return defaultValue;
T2 obj2 = func1(obj);
if (obj2 == null)
return defaultValue;
T3 obj3 = func2(obj2);
if (obj3 == null)
return defaultValue;
return func3(obj3);
}
public static TResult Coalesce<T1, T2, T3, T4, TResult>(this T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, T4> func3, Func<T4, TResult> func4, TResult defaultValue)
{
if (obj == null)
return defaultValue;
T2 obj2 = func1(obj);
if (obj2 == null)
return defaultValue;
T3 obj3 = func2(obj2);
if (obj3 == null)
return defaultValue;
T4 obj4 = func3(obj3);
if (obj4 == null)
return defaultValue;
return func4(obj4);
}
BinaryTreeNode node = LocateNode(someKey);
BinaryTreeNode grandFatherNode = node.Coalesce(n1 => n1.Parent, n2 => n2.Parent, null);
BinaryTreeNode grandFatherNode = node.Parent.Parent; // or null if none
coalesce(something, something_else, "default");
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;
}
public static Nullable<TResult> UntilNull<T, TResult>(T obj, Func<T, Nullable<TResult>> func) where TResult : struct
{
if (obj != null) return func(obj);
else return new Nullable<TResult>();
}
public static Nullable<TResult> UntilNull<T1, T2, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, Nullable<TResult>> func2) where TResult : struct
{
if (obj != null) return UntilNull(func1(obj), func2);
else return new Nullable<TResult>();
}
public static Nullable<TResult> UntilNull<T1, T2, T3, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, Nullable<TResult>> func3) where TResult : struct
{
if (obj != null) return UntilNull(func1(obj), func2, func3);
else return new Nullable<TResult>();
}
public static Nullable<TResult> UntilNull<T1, T2, T3, T4, TResult>(T1 obj, Func<T1, T2> func1, Func<T2, T3> func2, Func<T3, T4> func3, Func<T4, Nullable<TResult>> func4) where TResult : struct
{
if (obj != null) return UntilNull(func1(obj), func2, func3, func4);
else return new Nullable<TResult>();
}
}
int? length = customers?.Length; // null if customers is null Customer
first = customers?[0]; // null if customers is null
int length = customers?.Length ?? 0; // 0 if customers is null
int? first = customers?[0].Orders.Count();
int? first = (customers != null) ? customers[0].Orders.Count() : null;
int? first = customers?[0].Orders?.Count();
if (predicate?.Invoke(e) ?? false) { … }
PropertyChanged?.Invoke(this, args);