0

我正在编写一个通用的 C# 结构。我有以下内容:

struct GenericPoint<T> where T : IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T> {
  T x;
  T y;

  GenericPoint(T x, T y) {
    this.x = x;
    this.y = y;
  }

  static GenericPoint<T> operator +(GenericPoint<T> p1, GenericPoint<T> p2) {
    GenericPoint<T> r;
    r.x = (dynamic) p1.x + p2.x;
    r.y = (dynamic) p1.y + p2.y;
    return r;
  }

这会起作用,但有更好的方法吗?我的意图是 T 将是一种了解“+”运算符的类型。我很高兴在编译时做出这个承诺。但这可能吗?

4

3 回答 3

3

不幸的是,没有办法用 C# 泛型来做到这一点。

这就是为什么,例如,.NET框架提供PointPointFRectangleRectangleF等,其中这些结构的定义基本上是彼此的重复,带有intfloat代替想要的“通用”类型。


但是,如果你真的想这样做...

  1. 创建一个IMath<T>接口。(或者即使IField<T>你喜欢冒险。见这里:Field

    interface IMath<T>
    {
        T Zero { get; }
        T One { get; }
        T Negate(T a);
        T Add(T a, T b);
        T Sub(T a, T b);
        T Mult(T a, T b);
        //etc...
    }
    
  2. 修改GenericPoint<T>为具有对 a 的static引用IMath<T>

    struct GenericPoint<T>
    {
        public static IMath<T> TMath { get; set; }
        public T x;
        public T y;
        public static GenericPoint<T> operator +(GenericPoint<T> p1, GenericPoint<T> p2)
        {
            GenericPoint<T> r;
            r.x = TMath.Add(p1.x, p2.x);
            r.y = TMath.Add(p1.y, p2.y);
            return r;
        }
    }
    
  3. 在“程序初始化”期间,为您想要支持的每种类型设置GenericPoint<int>.TMathGenericPoint<float>.TMath等。T如果您不小心尝试将您的GenericPoint<T>类与您未指定的类型一起使用 a IMath<T>,您将NullReferenceException在使用运算符时得到 a 。

于 2013-10-05T04:10:32.710 回答
0

有一种稍微简单的方法。使用 Linq.Expressions 可以创建以通用方式执行所需数学运算的委托,假设如果类型不支持该操作,您愿意在运行时接受错误。这实际上更容易的唯一原因是它已经完成,请参阅:http ://www.yoda.arachsys.com/csharp/miscutil/

使用 Operator.cs 中定义的静态 Operator 类,您可以将动态转换替换为:

r.x = (dynamic) p1.x + p2.x;
r.y = (dynamic) p1.y + p2.y;

变成:

r.x = Operator<T>.Add(p1.x, p2.x);
r.y = Operator<T>.Add(p1.y, p2.y);
于 2013-10-05T07:03:23.393 回答
0

你想做的事你做不到(我希望能够做到)。问题是在 C# 接口中不允许运算符重载。因此,虽然您可以限制(http://msdn.microsoft.com/en-us/library/d5x73970.aspx)您的通用变量('T'),但如果您将其限制在一个接口上,它不会知道您有一个 ' +' 运算符。您可以定义一个基类,其中重载了适当的运算符,但是您必须将“T”限制为基于该类(因此您不能使用任何值类型,如 int、double 等),或不基于的对象用作约束的对象。您的动态解决方案实际上非常好,最大的问题当然是您短路了任何编译时警告,所以如果您使用不支持“+”的类,您将不会

于 2013-10-05T04:23:59.890 回答