为什么不能在泛型中要求操作符重载?

本文关键字:操作符 重载 不能 泛型 为什么 | 更新日期: 2023-09-27 17:53:49

在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,然后对所有对象运行类型检查)来完成,但这是低效的,并且不能很好地扩展。那么,为什么呢?

为什么不能在泛型中要求操作符重载?

不存在任何内在原因。实现泛型类型约束的方式是通过接口调用。如果有提供operator+的接口,这将工作。

这个接口对于所有相关类型都是必需的,但是,要像c++基于模板的类比一样通用。

另一个问题是。net没有多重分派。接口调用将是不对称的:a.Plus(b)可能意味着与b.Plus(a)不同的东西。顺便说一句,Equals也有同样的问题。

所以这个问题可能不符合"有用性"栏或"成本/效用"栏。这不是一个不可能的问题,而是一个实际的问题。

证明它是可能的:((dynamic)a) + ((dynamic)b) .

CLR本身不支持这样的约束,c#设计团队显然决定支持与CLR相同的约束集。大概CLR团队和c#团队都认为实现这样一个特性的好处并不会超过指定、实现和测试它的成本。

如果你想使用支持这些约束的。net语言,可以考虑一下f#。

有几种可能的方法来实现运算符约束,它们要么是不平凡的(并且可能需要更改CLR),要么有明显的缺点(例如,它们会很慢,比添加两个整数要慢得多)。

这是相对容易解决的问题(要么是使用dynamic的缓慢,一般和不安全的方式,要么是快速,特定类型和安全的方式进行大量重载)。正因为如此,这样的特性可能被认为是"有就好",但远没有重要到足以保证这样的更改。