我有一个Maybe
类型,我在代码I中使用它作为等同于Nullable
的引用类型。
定义为struct Maybe<T> where T : class
,它采用通常的HasValue
和Value
方法。
我想同时提供Map
和Bind
操作(与F#Option.map和Option.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
是多余的。
有趣的是,编译器似乎已经为Maybe
(reference)执行此操作:
其中T:struct type参数必须是值类型。可以指定除Nullable之外的任何值类型。有关详细信息,请参阅使用可空类型(C#编程指南)。
但是我认为已经开始了,并且没有办法让它以同样的方式对待我的Map
类型。
在这种情况下,有什么方法可以让类型推断工作吗?
我考虑过的变通办法,但我对此并不特别满意:
Bind
和{{1}}版本的名称不同。