【问题标题】:how to use where for operators at generics class c#? [duplicate]如何在泛型类 c# 中使用 where 运算符? [复制]
【发布时间】:2013-02-07 18:57:33
【问题描述】:

您好,我想上课:

class Matrix <T>
    where T : // I don't know what to write here
{
    T[][] elements;
}

我希望 T 可以被 + 和 * 运算符相加和相乘

【问题讨论】:

  • 不幸的是,对于实现特定运算符的类型没有约束。有一些我不会亲自使用的解决方法,例如转换为 dynamic
  • Constraint for only integers 可能的解决方案是IConvertible
  • 虽然是一个有趣的问题,但它是否可以通过隐式指定类型来工作(例如 int 的 iMatrix 和 float 的 fMatrix)?

标签: c# generics operator-keyword generic-constraints


【解决方案1】:

我强烈建议您查看 Messrs Skeet 和 Gravell 的“MiscUtil”库:

http://www.yoda.arachsys.com/csharp/miscutil/

其中包含一个令人难以置信的“通用数学运算符”实现,它应该与您创建通用矩阵数学类的尝试很好地对齐。它实际上让我(有点)想起了 python 以及它如何处理直接引用运算符函数。

(除了@jon-skeet :这有可能进入 Nuget 吗?)

他们的测试中的一些示例用法:

double sumOperator = 0;
for (int i = 0; i < COUNT; i++)
{
    sumOperator = Operator.Add(sumOperator, rand.NextDouble());
}

int sumOperator = 0;
for (int i = 0; i < COUNT; i++)
{
    sumOperator = Operator.Add(sumOperator, rand.Next(MAXVALUE));
}

【讨论】:

    【解决方案2】:

    这是不可能的,因为不受约束的泛型类型被假定为Object 类型,它没有定义算术运算符。因此,您似乎需要指定一个接口。

    但是,原始类型(Int32、Double 等)将算术运算有效地定义为静态方法(实际上编译器对其进行了特殊处理并生成内联代码),并且 C# 中的接口无法定义静态方法(尽管CLR 实际上允许它)。因此,没有用 C# 编写满足支持算术运算要求的接口;即使可以写,原始类型也不会继承它,所以它仍然无法工作。

    最终的结果是在 C# 中没有办法做你想做的事。

    如果你尝试一下,你会得到一个类似于

    的错误
    Operator '+' cannot be applied to operands of type 'T' and 'T'
    

    如果您对此邮件进行网络搜索,您会发现关于可能的解决方法的各种讨论。

    【讨论】:

      【解决方案3】:

      由于我不知道任何内置解决方案,请查看:

      public abstract class BaseClass
      {
          public static BaseClass operator +(BaseClass p1, BaseClass p2)
          {
              return p1 + p2;
          }
      
          public static BaseClass operator *(BaseClass p1, BaseClass p2)
          {
              return p1 * p2;
          }
      }
      
      public class ChildClass : BaseClass
      {
      }
      
      public class Matrix <T> where T : BaseClass
      {
          T[][] elements;
      }
      

      希望这会有所帮助。

      但是,不支持其他类型,例如int

      【讨论】:

      • 如果有另一个类支持+* 但不继承BaseClass 这将不起作用。例如int
      • @Default 确实,感谢您指出这一点。我已更新答案以添加此限制。
      【解决方案4】:

      可能这种方式会对某人有所帮助。您可以通过在 fabric-library 类中放置 add、multiplicate 函数来改进这一点。

      更新 可能会将来自 JerKimball 的 Operator 放入 counstructor

      class Matrix <T>
      {
          T[][] elements;
      
          public Matrix(Func<T, T, T> add, Func<T,T,T> multiplicate)
          {
              this.Add = add;
              this.Mult = multiplicate;
          }
      
          public Matrix<T> operator +(Matrix<T> p1, Matrix<T> p2)
          {
              // correct this
              var t = Add(p1.elements[0][0], p2.elements[0][0]);
              return this;
          }
      
          public Matrix<T> operator *(Matrix<T> p1, Matrix<T> p2)
          {
              // correct this
              var t = Mult(p1.elements[0][0], p2.elements[0][0]);
              return this;
          }
      
          private Func<T, T, T> Add { get; set; }
      
          private Func<T, T, T> Mult { get; set; }
      }
      
      static void Main(string[] args)
      {
          var m1 = new Matrix<int>((x,y) => x + y, (x,y) => x * y);
          var m2 = new Matrix<int>((x, y) => x + y, (x, y) => x * y);
      }
      

      更新 2

      只需像这样提供对属性的访问权限:

          public T[][] Elements { get; set; }
      

      你可以这样做:

      m1.Elements[0][0] = 10;
      var m3 = new Matrix<int?>((x, y) => x + y, (x, y) => x * y);
      m3.Elements[0][0] = null;
      

      【讨论】:

      • 这样我不能给元素赋值(比如 0 或任何数字,也不能将它们转换为 int 或任何不可为空的类型)
      • 你能举一个你不能做的例子吗?
      猜你喜欢
      • 2010-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多