所以我在C#lib中有这个:
public static TOut IfNotNull<TIn, TOut>
(this TIn instance, Func<TIn, TOut> func)
{
return instance == null ? default(TOut) : func(instance);
}
Run Code Online (Sandbox Code Playgroud)
使用如下:
DateTime? expiration = promo.IfNotNull(p => p.TermsAndConditions.Expiration)
.IfNotNull(e => e.Date);
Run Code Online (Sandbox Code Playgroud)
我一直在试图弄清楚如何使用C#4 dynamic关键字来启用此语法:
DateTime? expiration = promoOffer.TermsAndConditions.Maybe()
.Expiration.Maybe()
.Date;
Run Code Online (Sandbox Code Playgroud)
我有几个我认为有效的例子但是当你开始链接时它们就崩溃了Maybe().
有任何想法吗?
(我是在浪费时间吗?是Maybe()赢了IfNotNull()吗?)
我认为在这里使用dynamic类型不是一个好主意,因为语法看起来不会好得多,而且使用动态类型会牺牲类型安全(和 IntelliSense)。
但是,这里是您可以执行的操作的示例。这个想法是将对象包装到DynamicWrapper(你的一元值:-))中,它可以包含一个null值或一个实际值。它将继承DynamicObject并委托对实际对象的所有调用(如果有的话)或立即返回null(这将是单子绑定):
class DynamicWrapper : DynamicObject {
public object Object { get; private set; }
public DynamicWrapper(object o) { Object = o; }
public override bool TryGetMember(GetMemberBinder binder, out object result) {
// Special case to be used at the end to get the actual value
if (binder.Name == "Value") result = Object;
// Binding on 'null' value - return 'null'
else if (Object == null) result = new DynamicWrapper(null);
else {
// Binding on some value - delegate to the underlying object
var getMeth = Object.GetType().GetProperty(binder.Name).GetGetMethod();
result = new DynamicWrapper(getMeth.Invoke(Object, new object[0]));
return true;
}
public static dynamic Wrap(object o) {
return new DynamicWrapper(o);
}
}
Run Code Online (Sandbox Code Playgroud)
该示例仅支持属性,并且以相当低效的方式使用反射(我认为可以使用 DLR 对其进行优化)。以下是其工作原理的示例:
class Product {
public Product Another { get; set; }
public string Name { get; set; }
}
var p1 = new Product { Another = null };
var p2 = new Product { Another = new Product { Name = "Foo" } };
var p3 = (Product)null;
// prints '' for p1 and p3 (null value) and 'Foo' for p2 (actual value)
string name = DynamicWrapper.Wrap(p1).Another.Name.Value;
Console.WriteLine(name);
Run Code Online (Sandbox Code Playgroud)
请注意,您可以自由地链接调用 - 只有开头 ( Wrap) 和结尾 ( Value) 处有一些特殊的内容,但在中间,您可以编写.Another.Another.Another...任意多次。