为什么不能在泛型中要求运算符重载?

5
在C++中,您可以像这样编写代码:
template<class T>
T Add(T lhs, T rhs)
{
    return lhs + rhs;
}

但是在C#中不能像这样做:
public static T Add<T>(T x, T y) where T : operator+
{
    return x + y;
}

有什么原因吗?我知道可以通过反射实现(使用对象的通用Add,然后对所有内容进行类型检查),但这种方法效率低下且不易扩展。所以,再次问一遍,为什么?


这看起来像是 https://dev59.com/8XRA5IYBdhLWcg3w_DDF 的重复。 - neontapir
@neontapir 接受的答案使用了反射。我提到过我知道可以用那种方式来做,但我宁愿不这样做。 - Cole Tobin
我认为在第二段中你的意思是C#不能这样做,即问题是“为什么没有运算符重载类型约束?”(顺便说一下,我不知道答案)。 - The Dag
4
C++泛型不同于C#模板,并且行为也不相同。在Stack Overflow上询问“为什么”并不是一个好问题。 - asawyer
3个回答

5
这并非不可能。泛型类型约束是通过接口调用实现的。如果存在一个提供 operator+ 的接口,那么这将起作用。
然而,这个接口将需要适用于所有相关类型,才能像基于 C++ 模板的类似物一样通用。
另一个问题是 .NET 不能多重分配。接口调用将是不对称的:a.Plus(b) 可能意味着与 b.Plus(a) 不同的东西。顺便说一下,Equals 也有同样的问题。
因此,这个问题可能没有达到“实用性”的标准或“成本效益”的标准。这不是不可能的问题,而是实际问题。
证明它是可能的:((dynamic)a) + ((dynamic)b)

3
你没有提到一件事(至少不是明确地):不存在能够提供 operator+ 的接口,因为运算符必须是静态方法,而静态方法不能是接口的成员。 - svick
1
@svick 我在谈论一个假设的 .NET 未来版本。操作符可以增加实例方法版本。现在,你是正确的。 - usr

3

公共语言运行库(CLR)本身不支持这些限制条件,而C#设计团队显然决定支持与CLR相同的一组限制条件。 可能CLR团队和C#团队都认为实施此功能的好处并不超过规范、实施和测试的成本。

如果您想使用支持这些限制条件的.NET语言,请考虑查看F#。


尽管我相信 F# 仅在某些情况下支持此类约束(因为 CLR 约束的限制)。 - svick
1
@svick - F# 尽可能使用 CLR 约束,但它有自己的元数据格式来表示许多无法在 CLR 类型系统中表达的 F# 特定信息。其中之一是成员约束,它要求类型具有特定名称和签名的方法。 - kvb

0

有几种可能的方法来实现运算符约束,它们都不是微不足道的(并且可能需要更改CLR),或者有显着的缺点(例如,它们会很慢,比两个整数相加要慢得多)。

这是相对容易解决的问题(使用dynamic的缓慢、通用和不安全的方式,或者具有大量重载的快速、类型特定和安全的方式)。因此,这种功能可能被认为是“好的”,但远远不重要到足以保证进行此类更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接