为Nullable <>*和*引用类型实现monadic绑定

Tho*_*ith 0 c# monads extension-methods nullable

我有这个功能:

public static U? IfNotNull<T, U>(this T? self, Func<T, U?> func)
    where T : struct
    where U : struct
{
    return (self.HasValue) ? func(self.Value) : null;
}
Run Code Online (Sandbox Code Playgroud)

例:

int? maybe = 42;
maybe.IfNotNull(n=>2*n); // 84

maybe = null;
maybe.IfNotNull(n=>2*n); // null
Run Code Online (Sandbox Code Playgroud)

我希望它可以处理隐式可空引用类型以及显式Nullable<>类型.这种实现可行:

public static U IfNotNull<T, U>(this T? self, Func<T, U> func)
    where T : struct
    where U : class
{
    return (self.HasValue) ? func(self.Value) : null;
}
Run Code Online (Sandbox Code Playgroud)

但是,当然重载分辨率不会考虑类型约束,因此您不能同时使用两者.这个问题有方法解决吗?

Jon*_*eet 8

但当然,重载决策不会考虑类型约束

它确实......但不是方法本身的类型约束.它查看参数类型的类型约束.

在C#4(有可选参数)中你可以这样做......但我真的建议你不要这样做:

public class MustBeStruct<T> where T : struct {}
public class MustBeClass<T> where T : class {}

public static U? IfNotNull<T, U>(this T? self, Func<T, U?> func,
                       MustBeStruct<U> ignored = default(MustBeStruct<U>))
    where T : struct
    where U : struct
{
    return (self.HasValue) ? func(self.Value) : null;
}

public static U IfNotNull<T, U>(this T? self, Func<T, U> func,
                                MustBeClass<U> ignored = null)
    where T : struct
    where U : class
{
    return (self.HasValue) ? func(self.Value) : null;
}
Run Code Online (Sandbox Code Playgroud)

有关这个可怕,可怕的黑客的更多详细信息,请参阅此博客文章.

就个人而言,我可能只是将两种方法命名为不同,以便重载解析不需要如此努力 - 而且代码的读者也不需要.