【问题标题】:Operators in C# Generics [duplicate]C#泛型中的运算符[重复]
【发布时间】:2014-03-10 16:55:53
【问题描述】:

在 C++ 中我们可以这样写:

template <typename T>

    void Print(T a, T b) 
      {
          cout<<a+b<<endl;
      }

Print(12,56) or Print('c','s');

如果我们为用户定义的类型(类)重载运算符,我们也可以这样写:

Person a, b; Print(a,b);

但是在 C# 中我们不能编写诸如 + - 或 * / 之类的运算符 为什么我们不能写这个? 以及我们如何做到这一点(在通用方法中使用运算符)?

【问题讨论】:

  • C# 不支持这一点,因为 C# 泛型是类型系统的直接一部分。 (见约束)
  • " in C# we cant write operators such as + - or * /" 我们不能? msdn.microsoft.com/en-us/library/aa288467%28v=vs.71%29.aspx
  • @JacobKrall 如果您是泛型类,则不会。您不能指定泛型参数的约束。

标签: c# generics


【解决方案1】:

我们怎么做(在通用方法中使用运算符)

一般情况下,我们不能。对于大多数运算符,如果与类型参数(例如T)一起使用,编译器无法计算出适用的重载以在编译时使用。

如果您在基类(即在非密封的引用类型上)编写用户定义的运算符,则可以在有约束的情况下使用它们。例如System.Uri 是一个重载== 运算符的非密封类。那么如果你这样做:

class Test<T> where T : Uri
{
  internal void Method(T x, T y)
  {
    bool ok = x == y;
  }
}

使用了用户定义的重载。当然,其他运算符也是如此。

但通常您希望使用预定义的 值类型 和预定义的运算符来执行此操作,例如 T 是某种数字类型 (struct),而您想要 == (相等)或*(乘法)或&lt;&lt;(整数位移)或类似的。但这在 C# 中是不可能的。

可以使用dynamic 代替泛型类型,但显然这是完全不同的。

【讨论】:

    【解决方案2】:

    到目前为止,我发现的最佳解决方案是在 MiscUtils 库中。它使用表达式树在运行时执行操作。挺好的,性能也不错。

    您可以调用Operator.Add,而不是使用operator+。如果这两种类型公开了允许该操作的operator+,则调用将成功。并按预期工作。

    这是对 C# 泛型实现(以及 CLR)的不幸限制。更类似于 C++ 模板的东西有时会非常有用。

    【讨论】:

    • 好消息当然是 C# 泛型在编译时不会被解析,这与 C++ 模板不同。
    • @DaveVandenEynde:嗯,类型肯定是在编译时解决的,这就是为什么 OP 一开始就有这个问题。两种系统都有优点,但我更喜欢模板。他们更强大。在一般情况下使用泛型通常是令人愉快的,但有时会很痛苦。我用 C# 编写了一个图像处理库,并且会因为能够在一个函数中对来自不同图像类型的像素执行数学运算而不会增加一堆开销而死。
    • 实例化在编译时被解析,但泛型本身被编译成程序集。使用 C++ 模板,您可以包含整个模板、代码和所有内容,并且在实例化时对其进行编译。这是一个很大的区别。是的,C++ 模板更强大(我记得 operator() 在类上重载以非常喜欢将其作为函数传递)但是存在问题。泛型是一种不同的野兽,它的范围更小但更清晰。
    【解决方案3】:

    为什么我们不能写这个?

    因为这是语言规范所说的。

    怎么做(在通用方法中使用运算符)?

    我们不能。

    C# 的限制。

    关于根本原因 - 此处难以猜测且偏离主题(基于推测),但不支持运算符。期间。

    【讨论】:

    • 有一个非常简单的原因:无法指定具有运算符的类型。 (并且 CLR 不支持虚拟静态调用)
    • 对不起,没有真正的原因 - 这两者都可能被权力改变。
    猜你喜欢
    • 2015-05-23
    • 2014-01-01
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 2011-08-19
    • 1970-01-01
    相关资源
    最近更新 更多