【问题标题】:Generic types operators泛型类型运算符
【发布时间】:2016-06-10 06:47:10
【问题描述】:

我正在尝试创建坐标是通用的二维向量(Vector2Dint、Vector2Dfloat 等),以便能够更轻松地进行一些数学运算。我已经看到这个问题非常接近我的问题:Can't operator == be applied to generic types in C#? 但我的情况是使用“*”运算符。基本上我需要为这个向量做一些数学函数,比如“cross”或“dot”,一个例子就是这个:

    public static T cross<T>(Vec2<T> u, Vec2<T> v)
    {
        return u.x * v.y - u.y * v.x;
    }

事情是 Visual Studio 告诉我的相同:“运算符 '*' 不能应用于类型 'T' 和 'T' 的操作数”(T 是坐标的类型)。我的想法是重载“Vec2”类中的“*”运算符,以便能够将这些坐标相乘,如下所示:

    public static Vec2<T> operator *(T x, T y)
    {
        return x * y;
    }

但 Visual Studio 再次告诉我同样的事情。我确定我没有以正确的方式重载运算符,但我不知道原因。感谢您的帮助

编辑 1: 好的,我们可以从中学到的是,如果您想为不同类型(int、float、double 等)定义一个函数并且想要性能,最好的方法是为每种类型定义函数,但是现在,我遇到了另一个问题。如果你有一个很长的函数或几个很长的函数,¿这仍然是最好的方法吗?

【问题讨论】:

  • 你不知道 x 和 y 是什么类型,是什么让你认为他们有* 运算符?
  • 好吧,T 肯定是错的,如果你定义了一个 Vec2 那么你的操作符将是两个整数,你想将向量相乘,而不是两个整数,对吗?
  • 嗯,不完全是这样,我正在尝试创建一个函数来执行将向量的每个坐标相乘的“交叉”数学函数,这个坐标是通用的,它们是 int、float 和 double。当我尝试将坐标相乘时出现问题

标签: c# generics operators overloading


【解决方案1】:

您收到此错误是因为类型“T”未知。如您所知,它可以是字符串,也可以是任何类型的类或结构。

一种方法是为向量的所有“预期”类型提供重载

    public static int cross(Vec2<int> u, Vec2<int> v)
    {
        return u.x * v.y - u.y * v.x;
    }

    public static double cross(Vec2<double> u, Vec2<double> v)
    {
        return u.x * v.y - u.y * v.x;
    }

    public static long cross(Vec2<long> u, Vec2<long> v)
    {
        return u.x * v.y - u.y * v.x;
    }

    public static float cross(Vec2<float> u, Vec2<float> v)
    {
        return u.x * v.y - u.y * v.x;
    }

    ...

【讨论】:

  • 我认为这是最好的方法,如果预期的类型只有 4 我可以处理。
  • @daolmed 4 种类型是否足够由您决定。 .net 中有十几种数值类型
【解决方案2】:

嗯,这是一种非常丑陋的方法,我永远不会将它用于游戏(速度),但它可以满足您的要求:

你的 Vec2 类:

    public class Vec2<T>
    {
        public T x;
        public T y;

        public static Vec2<T> operator *(Vec2<T> u, Vec2<T> v)
        {
            return u.Cross(v);
        }
    }

还有一个扩展类:

    public static class Exts
    {
        public static T Cross<T>(this Vec2<T> u, Vec2<T> v)
        {

            if (u.x is double)
                return (T)Convert.ChangeType(Convert.ToDouble(u.x) * Convert.ToDouble(v.y) - Convert.ToDouble(u.y) * Convert.ToDouble(v.x), typeof(T));
            else if (u.y is float)
                return (T)Convert.ChangeType(Convert.ToSingle(u.x) * Convert.ToSingle(v.y) - Convert.ToSingle(u.y) * Convert.ToSingle(v.x), typeof(T));
            else if (u.x is decimal)
                return (T)Convert.ChangeType(Convert.ToDecimal(u.x) * Convert.ToDecimal(v.y) - Convert.ToDecimal(u.y) * Convert.ToDecimal(v.x), typeof(T));
            else
                return (T)Convert.ChangeType(Convert.ToInt32(u.x) * Convert.ToInt32(v.y) - Convert.ToInt32(u.y) * Convert.ToInt32(v.x), typeof(T));

        }
    }

【讨论】:

  • 非常感谢您的回答,但您是对的,是为了游戏!
  • 那么,我的两分钱,永远不要在游戏中使用泛型,在像 Vector 类这样的情况下更少,因为你将拥有数千个,它们比直接类慢。
【解决方案3】:

目前无法告诉编译器哪些运算符可以用于泛型类型参数。以多种方式扩展通用约束的问题正在github in the C# compiler repository 上标题为有趣但需要 CLR 支持的段落下讨论。

您也可以在Visual Studio Uservoice上投票支持添加此功能

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-16
    • 2016-01-25
    • 1970-01-01
    • 2011-02-03
    • 2018-10-19
    • 1970-01-01
    相关资源
    最近更新 更多