【问题标题】:C# Operator Overloading Using Generic's Subclass使用泛型子类的 C# 运算符重载
【发布时间】:2017-06-07 11:18:45
【问题描述】:

我有一个如下所示的结构:

public struct Vector2d<T> where T : Unit {
    public double x;
    public double y;

    ...

    public static Vector2d<Length> operator * (Vector2d<Speed> speed, Vector2d<Duration> duration) {
        return new Vector2d<Length>(speed.x * duration.x, speed.y * duration.y);
    }
}

长度、速度和持续时间类型都是单位的子类型。 (T 也继承自 Unit)

但是,编译器说:

二元运算符的参数之一必须是包含类型。

这让我觉得很奇怪,因为提供的类型是包含类型的子类。

为什么我试图做的事情是非法的?

我知道 Vector2 不是 Vector2 的子类,但我并没有尝试使用泛型类型的值。算子中用到的所有数据都是Vector2类。

【问题讨论】:

  • 这是非法的,因为语言设计者将其设为非法。错误消息准确地告诉您 C# 规范描述的约束。编译器只是遵循规范。如果你想知道“为什么?”您需要询问语言设计者,即便如此,他们的推理也可能主要基于他们自己的意见。
  • 不知道为什么这个问题被否决了......完全有效的问题与代码和明确的问题。来自我的 +1。
  • 我建议不要尝试通过泛型来表示单元分析。单元是真正需要内置到语言中的东西。例如,参见 F#​​ 的单元类型注释。 docs.microsoft.com/en-us/dotnet/articles/fsharp/…

标签: c# generics operator-overloading operators


【解决方案1】:

根据MSDN page这个错误:

二元运算符的定义指定两个参数的类型不同于定义运算符的类或结构的类型。 在类或结构中定义运算符时,至少有一个参数必须是该类或结构的类型。

在您的情况下,您的操作员没有使用 Vector2d&lt;T&gt; 类型(您正在使用 Vector2d&lt;Speed&gt;Vector2d&lt;Duration&gt;

【讨论】:

  • 因此运算符必须应用于该类型的所有实例,而不仅仅是一个子集。明白了。
【解决方案2】:

运算符对声明它们的类型的实例进行操作。例如:

string one = new string(new char[] { 'o', 'n', 'e' });
string two = new string(new char[] { 't', 'w', 'o' });
if (one == two) { // do something... };

我之所以能够使用== 是因为它是在String 类中实现的。

您的班级中还有一个操作员。所以让我们使用它。但要做到这一点,我需要创建一个Vector2d&lt;T&gt; 的实例,因为它是一个开放类型,我需要在实例化过程中关闭它。

所以让我们先这样做:

public class MyClass : Unit
{
}

现在让我们创建一个结构实例:

var inst1 = new Vector2d<MyClass>();
var inst2 = new Vector2d<MyClass>();

之所以有效,是因为MyClass 正在通过T 必须从Unit 派生的限制。好的,现在我将使用运算符:

// Ooops MyClass is not Speed or Duration
var result = inst1 * inst2; 

这正是编译器强制执行该规则的原因,因为它希望确保运算符可以对类型的实例进行操作。

在您的情况下,您只能像这样定义Vector2d&lt;T&gt; 的运算符:

public struct Vector2d<T> where T : Unit
{
    public double x;
    public double y;

    public Vector2d(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public static Vector2d<T> operator *(Vector2d<T> speed, Vector2d<T> duration)
    {
        return new Vector2d<T>(speed.x * duration.x, speed.y * duration.y);
    }
}

此外,您的运营商,您拥有它的方式根本不是通用的。它正在使用SpeedDurationLength,因此您正在使用这些类型。

错误二元运算符的参数之一必须是包含类型。是编译器避免我们陷入此类麻烦的方法。我们应该感恩!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 2018-10-19
    • 2011-05-01
    • 2015-05-23
    • 2016-01-25
    • 1970-01-01
    • 2012-12-10
    • 2017-04-28
    相关资源
    最近更新 更多