使用generics类型的任何优雅方式?

我正在一个小型教育项目中工作,我们必须实现一个n维矩阵。 根据上下文,此矩阵要么使用我们自己的内置ComplexNumber结构,要么使用System.Double ,对于非常简单的示例,使用整数类型(主要是System.Int32 )。

由于应用程序的性质,我们不需要实现闪电般快速的性能。

因此,我的第一个想法是实现一个Matrix ,其中T将以某种方式被限制为“数字”

这样做的一个明显问题是,语言中没有办法用定义的运算符约束generics类型T 另外,我没有看到将T为合理类型的简单方法。

我的问题是:

  1. 有人可以指点我用一种优雅的方式来进行数学运算,使用generics类型,不会过多地影响性能,并以某种方式使其与内置类型(如果可能)一起工作。

  2. 如果Eric读过这篇文章,那么这个function(通过定义的运算符约束generics类型)是否会出现在C#设计会议的假设未来版本中,并且它是否已经接近将其纳入语言?

我知道实现ComplexMatrix类型更简单,更好,并为每个矩阵“子类型”(double,integral等)创建包装器,并支付我们的复杂类型和矩阵元素中任何类型之间转换的性能成本碰巧是。 这个问题更多的是出于对某人如何实施类似场景的好奇心。

如果埃里克读过这个,

如果您想要引起我注意的事情,请尝试我博客上的联系链接。 或者将我的全名写在问题的文本中, 以便我搜索自己会找到我 。

这个function(通过定义的运算符约束generics类型)是否会出现在C#设计会议的假设未来版本中,并且它是否已经接近使用它成为语言?

实际上,这是一个经常被要求的function。 自C#1.0以来,我们一直在收到这类事情的请求。

该function需要CLR团队的支持,而不仅仅是语言 – 这是我们希望集成到所有语言中的一种function,这会增加成本。

CLR团队已经对这样的function表示了兴趣,但是他们也有很多竞争function,他们可以做,以及实现这些function的时间和精力有限。

有许多方法可以实现这样的function。 例如,我们可以添加在接口中指定静态方法的function:

 interface IAddable { static T operator+(T x, T y); } 

然后

 static T Sum(IEnumerable seq) where T : IAddable { T sum = default(T); foreach(T item in seq) sum = sum + item; return sum; } 

我们的想法是接口意味着“实现此接口的类型必须具有给定的静态方法”。 然后我们让int自动实现IAddable ,依此类推。

如何在运行时生成的通用代码的世界中如此有效地这是一个悬而未决的问题。

我赶紧补充一点,这只是一个想法的草图。 有很多方法可以实现这种function。 “界面中的静态”理念是一种比数学更广泛使用的理念,这对我们很有吸引力。 如果我们要付出这种function的巨大代价,那么拥有一个非常通用,强大的function而不是一个专注于数学的function将会很棒。

另一方面,完美是善的敌人; 最好只关注数学问题而不是寻求更昂贵的通用解决方案。

这是一场持续的辩论。 它肯定在每个人的雷达屏幕上,但我不希望它很快。 语言设计人员都在努力完成异步CTP的反馈。

与往常一样,埃里克关于假设未经宣布的未来产品的假设未来语言特征的思考仅用于娱乐目的。

实现此目标的唯一方法有点半优雅如下:让调用者为所需的运算符指定委托并使用这些委托。

例如:

 class Matrix { Func _add; Func _subtract; // ... public Matrix(Func add, Func subtract, ...) { _add = add; _subtract = subtract; // ... } } var m = new Matrix((a,b) => a+b, (a,b) => ab, ...); // Assuming that ComplexNumber has two static methods Add and Subtract var m = new Matrix(ComplexNumber.Add, ComplexNumber.Subtract, ..); 

但是,我不知道这种方法的表现……

这取决于你对什么是优雅的想法。 如果你的优雅想法能够写出a+b ,其中ab是generics类型,那将是我的优雅想法,那么这是不可能完成的。

遗憾的是,C#generics无法为这类代码实现C ++模板的优雅。

一个具有良好性能的解决方法(仍然很丑陋)是使用一个封装所需算术行为的结构。

首先定义一个接口:

 public interface IArithmetic { T Add(T n1,T n2); } 

然后使用struct实现该接口:

 public struct DoubleArithmetic:IArithmetic { public double Add(double n1,double n2) { return n1+n2; } } 

最后,将struct作为generics参数传递给您的类型:

 public class Matrix where TArithmetic:struct, IArithmetic { private static readonly TArithmetic arithmetic=new TArithmetic(); void DoStuff() { arithmetic.Add(1,2); } } 

我没有对它进行基准测试,但我怀疑它是相当快的,因为generics专门针对传递给它的每个值类型。 这就是DoubleArithmetic是一个struct的原因。