数学和generics
好的,我需要实现这两种特殊类型: ComplexNumber
和Matrix
。 T
可以是以下之一: 有理数 , 实数或整数。
在System命名空间中,我对实数( decimal
),整数( int
或long
)有很好的表示。 Numerics.ComplexNumber
不会削减它,因为内部RealPart
和ImaginaryPart
是double
,在这种特殊情况下,我不能承受这种类型的表示错误。
现在,探测器当然是没有办法将通用参数T
约束到数学“有效”类型。 也就是说,我不能做到以下几点:
public struct ComplexNumber { readonly T realPart; readonly T imaginaryPart; public static ComplexNumber Add(ComplexNumber left, ComplexNumber right) { return new ComplexNumber(left.realPart + right.realPart, left.imaginaryPart + right.imaginaryPart); //Compile time error. No operator defined for T } }
所以我需要一个解决方法。 虽然性能本身并不是目标,但我希望代码能够合理地运行,但最重要的是,我希望它能成为最优雅的解决方案。 现在我想出了两种可能性:
一个Numeric
抽象基类,类似于:
public abstract class Numeric { protected abstract Numeric _Add(Numeric right); protected abstract Numeric _Subtract(Numeric right); public static Numeric Add(Numeric left, Numeric right) { return _Add(this, right); } public static Numeric Subtract(Numeric left, Numeric right) { return _Subtract(this, right); }
现在我能做到:
public sealed class RationalNumber: Numeric { readonly long numerator, denominator; protected override Numeric _Add(Numeric right) { //Rational addition implementation } }
然后Matrix
或Matrix
将起作用。
另一种选择是通过接口来完成:
public INumeric { INumeric Add(INumeric right); INumeric Subtract(INumeric right); } public struct RationalNumber: INumeric { readonly long numerator, denominator; public static RationalNumber Add(RationalNumber left, RationalNumber right) { //Rationa add implementation } INumeric INumeric.Add(INumeric right) //explicit to not clog up the type and to convey the idea of a framework mechanism. { if (!(right is RationalNumber)) throw new ArgumentException(); Add(this, (RationalNumber)right); }
接口选项允许我将RationalNumber
实现为一个结构,即恕我直言,更符合框架中数字类型的实现方式。 这些类型本身也非常轻巧,通常寿命很短。 Numeric
基类解决方案看起来像是一个更重要的重量级,但是我并不是一个专家来准确量化一个优于另一个的优势:
- 代码质量和未来的可扩展性和维护
- 性能和内存消耗(好奇心比什么都重要)
- 更好的解决方案?
如果有人可以轻松一点,我会很感激。
您可以使用扩展方法来解决此问题:
public struct ComplexNumber { private readonly T _realPart; private readonly T _imaginaryPart; public ComplexNumber(T realPart, T imaginaryPart) { _realPart = realPart; _imaginaryPart = imaginaryPart; } public T RealPart { get { return _realPart; } } public T ImaginaryPart { get { return _imaginaryPart; } } public override string ToString() { return string.Format("({0}, {1})", RealPart, ImaginaryPart); } } public static class ComplexNumberExtensions { public static ComplexNumber Add(this ComplexNumber self, ComplexNumber other) { return new ComplexNumber (self.RealPart + other.RealPart, self.ImaginaryPart + other.ImaginaryPart); } public static ComplexNumber Add(this ComplexNumber self, ComplexNumber other) { return new ComplexNumber (self.RealPart + other.RealPart, self.ImaginaryPart + other.ImaginaryPart); } // Add similar extension methods for each numeric type you need }
像这样用它:
var first = new ComplexNumber(1, 2); var second = new ComplexNumber (3, 4); var result = first.Add(second); Console.WriteLine(result);