我是C#的新手,并且在尝试对模板类型应用方差限制时遇到了一些实际问题。也许它不可能是唯一的&#34; Where&#34;我可以从我的研究中找到的子句例子更多地基于向另一个方向发展(即。&#34;可从&#34;分配)。我已经列出了我试图模拟的Scala函数 - 关键是要确保T可以分配给U(即T <:U),所以无论如何返回值都是U.任何有关C#差异的帮助或提示都表示赞赏,谢谢
interface Option<out T> // where T : class
{
T GetUnsafe();
Option<X> map<X>(Func<object,Option<X>> f);
U GetOrElse<U>(U u) where T:U ; //What is wrong here,how do I get U:>T ?
bool IsSome { get; }
}
Scala选项示例[A] final def getOrElse [B&gt;:A](默认值:⇒B):B
作为更新,这里有一个工作版本作为静态功能 - 我只是无法弄清楚它是否可以作为方法
static class Option
{
public static U GetOrElse<T, U>(Option<T> o, U defAns) where T : U
{
if (o.IsSome) return o.GetUnsafe(); else return defAns;
}
答案 0 :(得分:1)
首先,您似乎将“泛型差异”与“泛型类型约束”混合在一起。是的,C#与Java或Scala不同,它只在一个方向上支持与继承相关的类型约束:您可以指定基类(但您可以执行Scala和Java支持的操作,例如new
约束)。有关详细信息,请参阅where (generic type constraint) (C# Reference)。由于T
在外部作用域中定义,因此您无法在内部作用域中为其添加其他约束。这就是您的示例无法编译的原因。第二个使用静态方法的示例进行编译,因为C#编译器足够智能,可以在声明中重新排序泛型类型,这样就可以使用已知类型(T
)定义约束(对于U
) 。
我不确定getOrElse
Scala方法的设计的实际用法是什么,因为Option
是协变的,即如果你想获得B
类型的值即使其实际类型为A
,也只需将var
声明为类型Option[B]
即可。所以我认为不要复制这一点逻辑不会是一大损失。
通常我认为您不能轻易地复制这样的代码,而是完全保留从Scala到C#的行为,但对于这种特殊情况,此方法只有一个您不需要覆盖的固定实现,您可以扩展静态使用extension methods的技巧:
public static class OptionHelper
{
public static U GetOrElse<T, U>(this Option<T> o, U defAns)
where T : U
{
if (o.IsSome) return o.GetUnsafe(); else return defAns;
}
}
由于在参数之前有额外的this
关键字,你可以使用它,好像它是在接口本身中定义的(有点类似于Java 8中的默认方法以及在Scala中使用隐式转换可以获得的内容):< / p>
Option<string> o = ..;
object value = o.GetOrElse(new object());