“实数”类型是否存在C#泛型约束?

时间:2009-08-28 18:18:38

标签: c# generics constraints

  

可能重复:
  C# generic constraint for only integers

电贺!

我正在尝试在C#中设置笛卡尔坐标系,但我不想将自己限制为我的坐标值的任何一种数值类型。有时它们可​​能是整数,有时它们可​​能是有理数,取决于上下文。

这对我来说是“通用类”,但我对如何将类型限制为积分和浮点感到难过。我似乎无法找到涵盖任何实数概念的课程......

public class Point<T> where T : [SomeClassThatIncludesBothIntsandFloats?]  {
    T myX, myY;

    public Point(T x, T y) {
        myX = x;
        myY = y;
    }
}

Point<int> pInt = new Point<int>(5, -10);
Point<float> pFloat = new Point<float>(3.14159, -0.2357);

如果我想要这种自由度,那么当我在课堂上进行计算,除去bool,字符串,对象等时,我是否选择了“typeof(T)”噩梦?或者更糟糕的是,我是否选择为我想要使用的每种类型的数字创建一个类,每个都有相同的内部数学公式?

任何帮助将不胜感激。谢谢!

8 个答案:

答案 0 :(得分:16)

您无法定义此类约束,但可以在运行时检查类型。但这对你的计算没有帮助。

如果你想进行计算,可以选择这样的选项:

class Calculations<T, S> where S: Calculator<T>, new()
{
    Calculator<T> _calculator = new S();

    public T Square(T a)
    {
        return _calculator.Multiply(a, a);
    }

}

abstract class Calculator<T>
{
    public abstract T Multiply(T a, T b);
}

class IntCalculator : Calculator<int>
{
    public override int Multiply(int a, int b)
    {
        return a * b;
    }
}

同样,定义FloatCalculator以及您需要的任何操作。虽然比C#4.0 dynamic构造更快,但速度并不是特别快。

var calc = new Calculations<int, IntCalculator>();
var result = calc.Square(10);

副作用是,如果传递给它的类型具有匹配的Calculator实现,则只能实例化Calculator<T>,因此您不必执行运行时类型检查。

这基本上是Hejlsberg在讨论问题的this interview中提到的内容。就个人而言,我仍然希望看到某种基本类型:)

答案 1 :(得分:12)

这是一个非常常见的问题;如果您使用的是.NET 3.5,那么MiscUtil中有很多支持,通过Operator类,它支持内置类型和任何带有运算符的自定义类型(包括“提升”运算符);特别是,这允许与泛型一起使用,例如:

public static T Sum<T>(this IEnumerable<T> source) {
    T sum = Operator<T>.Zero;
    foreach (T value in source) {
        if (value != null) {
            sum = Operator.Add(sum, value);
        }
    }
    return sum;
}

或者另一个例子; Complex<T>

答案 2 :(得分:7)

这是一个已知问题,因为没有一个算术类来自同一个类。所以你不能限制它。

你唯一能做的就是

where T : struct

但这不完全是你想要的。

以下是特定问题的链接。

Arithmetic types like int,double,decimal should implement IArithmetic<T>

答案 3 :(得分:3)

你实际上可以做到这一点,虽然解决方案设置起来很繁琐,并且可能会让那些不知道为什么会这样做的开发人员感到困惑。 (所以,如果你选择这样做,那就完全记录下来了!)......

创建两个结构,名为say,MyInt和MyDecimal,它们充当CTS Int32的外观,以及十进制核心类型(它们包含相应类型的内部字段。)每个结构都应该有一个ctor,它接受一个实例核心CTS类型作为输入参数..

使每个实现一个名为INumeric

的空接口

然后,在您的泛型方法中,根据此接口创建约束。 在下方,除了要使用这些方法之外,还必须构造适当的自定义类型的实例而不是Core CTS类型,并将自定义类型传递给方法。

注意:编写自定义结构以正确模拟核心CTS类型的所有行为是繁琐的部分......您必须实现几个内置的CLR接口(IC Comparable等)并重载所有算法,并且布尔运算符...

答案 4 :(得分:1)

您可以更加接近实施更多

public class Point<T> where T : struct, IComparable, IFormattable, IConvertible, 
                                IComparable<T>, IEquatable<T> {   
}

签名也符合DateTime。我不确定您是否能够从框架中指定更多类型。无论如何,这只能解决部分问题。要执行基本数值运算,您必须包装数字类型并使用泛型方法而不是标准运算符。 See this SO question有几个选项。

答案 5 :(得分:0)

Thi可能会有所帮助。你必须使用泛型类来实现你想要的目标。

答案 6 :(得分:0)

C#目前不允许对值类型进行类型约束。我不久前问了一个相关的问题。

Enum type constraints in C#

答案 7 :(得分:0)

这不适合实现IPoint的单独类吗?

类似的东西:

public interface IPoint<T>  
{
    T X { get; set; }
    T Y { get; set; }
}

public class IntegerPoint : IPoint<int>
{

    public int X { get; set; }
    public int Y { get; set; }
}

因为每次实施的计算都必须不同吗?

丹#