C# 在泛型中实现算术?

C# 在泛型中实现算术?,c#,.net,generics,C#,.net,Generics,有没有可能像你一样在C#泛型中实现基本的算术(至少是加法)?我已经尝试了一段时间让它们运行起来,但是C#不允许您多次声明相同的泛型类型,就像使用模板一样 大量的谷歌搜索并没有提供答案 编辑:谢谢,但我要寻找的是一种在编译时执行算术的方法,在泛型类型中嵌入类似于Church数字的东西。这就是为什么我链接了我写的那篇文章。泛型类型中的算术,而不是泛型类型实例中的算术。如果我的答案不正确,请随时提供更多说明 至少在C#语言中没有对运算符的通用约束。正如Jon Skeet所证明的,约束实际上可能在CLR

有没有可能像你一样在C#泛型中实现基本的算术(至少是加法)?我已经尝试了一段时间让它们运行起来,但是C#不允许您多次声明相同的泛型类型,就像使用模板一样

大量的谷歌搜索并没有提供答案

编辑:谢谢,但我要寻找的是一种在编译时执行算术的方法,在泛型类型中嵌入类似于Church数字的东西。这就是为什么我链接了我写的那篇文章。泛型类型中的算术,而不是泛型类型实例中的算术。

如果我的答案不正确,请随时提供更多说明

至少在C#语言中没有对运算符的通用约束。正如Jon Skeet所证明的,约束实际上可能在CLR本身中完全有效

使用约束所能做的最好的事情就是提供接口/自定义类来公开所需的操作。您将无法提供原语(除非您还实现了
隐式
操作符),但它至少可以让您为数学部分创建通用代码

泛型约束允许编译器根据最低公分母(由约束指定或缺少)推断可用成员。大多数情况下,泛型是不受约束的,因此只提供
object
语义。
或者,避免使用约束,并使用
dynamic
临时存储泛型变量,然后(通过duck键入)假设它具有相关运算符:

class Program
{
    static void Main(string[] args)
    {
        var result = Add<int, long, float>(1, 2);
        Console.WriteLine(result); // 3
        Console.WriteLine(result.GetType().FullName); // System.Single
        Console.Read();
    }

    static T3 Add<T1, T2, T3>(T1 left, T2 right)
    {
        dynamic d1 = left;
        dynamic d2 = right;
        return (T3)(d1 + d2);
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var结果=加(1,2);
Console.WriteLine(结果);//3
Console.WriteLine(result.GetType().FullName);//System.Single
Console.Read();
}
静态T3添加(T1左侧,T2右侧)
{
动态d1=左;
动态d2=右侧;
返回(T3)(d1+d2);
}
}
这涉及到DLR,并且会有一些性能开销(我没有确切的数字),特别是如果您希望计算是性能关键的。
我不确定“多次声明相同的泛型类型”是什么意思,这是有效的:

class Tuple<T1, T2> // etc.

var myTuple = new Tuple<int, int>(1, 2);
类元组//等。
var myTuple=新元组(1,2);

不幸的是,您不能对泛型类型使用算术运算

T Add(T a, T b)
{
    return a + b; // compiler error here
}
在c#中不起作用

但您可以创建自己的数值类型并重载运算符(算术、等式和
隐式
显式
)。这可以让你以一种非常自然的方式处理它们。但是,不能使用泛型创建继承层次结构。您必须使用非泛型基类或接口

我只是用向量类型做的。这里有一个简短的版本:

public class Vector
{
    private const double Eps = 1e-7;

    public Vector(double x, double y)
    {
        _x = x;
        _y = y;
    }

    private double _x;
    public double X
    {
        get { return _x; }
    }

    private double _y;
    public double Y
    {
        get { return _y; }
    }

    public static Vector operator +(Vector a, Vector b)
    {
        return new Vector(a._x + b._x, a._y + b._y);
    }

    public static Vector operator *(double d, Vector v)
    {
        return new Vector(d * v._x, d * v._y);
    }

    public static bool operator ==(Vector a, Vector b)
    {
        if (ReferenceEquals(a, null)) {
            return ReferenceEquals(b, null);
        }
        if (ReferenceEquals(b, null)) {
            return false;
        }
        return Math.Abs(a._x - b._x) < Eps && Math.Abs(a._y - b._y) < Eps;
    }

    public static bool operator !=(Vector a, Vector b)
    {
        return !(a == b);
    }

    public static implicit operator Vector(double[] point)
    {
        return new Vector(point[0], point[1]);
    }

    public static implicit operator Vector(PointF point)
    {
        return new Vector(point.X, point.Y);
    }

    public override int GetHashCode()
    {
        return _x.GetHashCode() ^ _y.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        var other = obj as Vector;
        return other != null && Math.Abs(other._x - _x) < Eps && Math.Abs(other._y - _y) < Eps;
    }

    public override string ToString()
    {
        return String.Format("Vector({0:0.0000}, {1:0.0000})", _x, _y);
    }
}
公共类向量
{
私人建筑双Eps=1e-7;
公共向量(双x,双y)
{
_x=x;
_y=y;
}
私人双x;
公共双X
{
获取{return\ux;}
}
私人双人房;
公共双Y
{
获取{return\u y;}
}
公共静态向量运算符+(向量a、向量b)
{
返回新向量(a.x+b.x,a.y+b.y);
}
公共静态向量运算符*(双d,向量v)
{
返回新向量(d*v.\ux,d*v.\uy);
}
公共静态布尔运算符==(向量a、向量b)
{
if(ReferenceEquals(a,null)){
返回ReferenceEquals(b,null);
}
if(ReferenceEquals(b,null)){
返回false;
}
返回Math.Abs(a.x-b.x)
朋友们,C#中对此的直观答案是RTTI和对象类的来回转换

enter code here

class MyMath
{
    public static T Add<T>(T a, T b) where T: struct
    {
        switch (typeof(T).Name)
        {
            case "Int32":
                return (T) (object)((int)(object)a + (int)(object)b);
            case "Double":
                return (T)(object)((double)(object)a + (double)(object)b);
            default:
                return default(T);
        }
    }
}

class Program
{
    public static int Main()
    {
        Console.WriteLine(MyMath.Add<double>(3.6, 2.12));
        return 0;
    }
}
在此处输入代码
我的数学课
{
公共静态T Add(ta,tb),其中T:struct
{
开关(类型(T).名称)
{
案例“Int32”:
返回(T)(对象)((int)(对象)a+(int)(对象)b);
“双重”情况:
返回(T)(对象)(双)(对象)a+(双)(对象)b);
违约:
返回默认值(T);
}
}
}
班级计划
{
公共静态int Main()
{
Console.WriteLine(MyMath.Add(3.6,2.12));
返回0;
}
}

是的,可以通过使用动态类型变量来完成

例如:

T Add(T value1, T value2)
{           
        dynamic a = value1;
        dynamic b = value2;
        return (a + b);
}

有关更多参考信息,请

很遗憾,类型约束不允许您要求该类型支持算术运算符。我发现有趣的是,在诸如
Int32
的BCL源代码中,您将在注释掉的继承列表中找到
IArithmetic
接口。这纯粹是我的猜测,但如果Microsoft在BCL中启用了该接口,那么您可能可以指定
IArithmetic
作为一个约束,允许您使用算术编写自己的泛型类。链接到类似的问题:什么是指“
struct
不允许约束”?您实际上可以这样做。请参阅。@Adamhuldsworth:结构可以实现接口!由于结构不能相互继承,因此限制为某个结构类型与