如何为Maybe和Nullable以相同的名称实现Map和Bind操作?

时间:2014-06-26 17:18:25

标签: c# generics

我有一个Maybe类型,我在代码I中使用它作为等同于Nullable的引用类型。

定义为struct Maybe<T> where T : class,它采用通常的HasValueValue方法。

我想同时提供MapBind操作(与F#Option.mapOption.bind具有相同的行为),我想同时实现这两种操作名称IfHasValue

我不仅要为IfHasValue()实现Maybe,还要为Nullable实现var maybeValue = Maybe.WithValue("some string"); int? nullableValue = 42; maybeValue.IfHasValue(x => x.Length).ShouldEqual(11); maybeValue.IfHasValue(x => (int?)x.Length).ShouldEqual(11); maybeValue.IfHasValue(x => x + " more").Value.ShouldEqual("some string more"); maybeValue.IfHasValue(x => Maybe.WithValue(x + " more")).Value.ShouldEqual("some string more"); nullableValue.IfHasValue(x => x + 1).ShouldEqual(43); nullableValue.IfHasValue(x => (int?)x + 1).ShouldEqual(43); nullableValue.IfHasValue(x => x.ToString(CultureInfo.InvariantCulture)).Value.ShouldEqual("42"); nullableValue.IfHasValue(x => Maybe.WithValue(x.ToString(CultureInfo.InvariantCulture))).Value.ShouldEqual("42"); ,并允许从类到结构的映射(和绑定),反之亦然。

基本上我希望所有这些测试都能编译并通过:

maybeValue.IfHasValue(x => Maybe.WithValue(x + " more")).Value.ShouldEqual("some string more");

我遇到的问题是,在这种情况下

public static Maybe<TOut> IfHasValue<TIn, TOut>(this Maybe<TIn> maybe, Func<TIn, Maybe<TOut>> selector)
    where TIn : class where TOut : class {}

// Note that in the full implementation I use the delegate trick to avoid
// this overload conflicting with the `TOut : class` version, but I omitted it
// since it's not needed for the overloads under discussion here.
public static TOut? IfHasValue<TIn, TOut>(this Maybe<TIn> maybe, Func<TIn, TOut> selector)
    where TIn : class where TOut : struct {}

类型推断无法确定这两个重载中的哪一个是

Maybe

因为我的Maybe类型是一个结构,我不能通知编译器如果选择器的结果是Maybe那么Nullable<Maybe<>>(第一个)重载应该总是被使用,因为Nullable是多余的。

有趣的是,编译器似乎已经为Maybereference)执行此操作:

  

其中T:struct type参数必须是值类型。可以指定除Nullable之外的任何值类型。有关详细信息,请参阅使用可空类型(C#编程指南)。

但是我认为已经开始了,并且没有办法让它以同样的方式对待我的Map类型。

在这种情况下,有什么方法可以让类型推断工作吗?

我考虑过的变通办法,但我对此并不特别满意:

  • Bind和{{1}}版本的名称不同。
  • 在这种情况下需要明确指定类型参数。

0 个答案:

没有答案