动态关键字启用"也许"monad?

Can*_*ain 5 c# dynamic

所以我在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()吗?)

Tom*_*cek 2

我认为在这里使用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...任意多次。