c#模板化整数方法?

c#模板化整数方法?,c#,C#,是否可以为任何类型的整数大小设置模板方法 为了举例说明,想象一下这个非常简单的例子(在我的问题中,方法的主体并不重要): 现在,我想要支持任何类型整数的相同方法(当然不包括BigInteger)。我必须写出所有变体: public long Mul(long a, long b) { return a*b; } public ulong Mul(ulong a, ulong b) { return a*b; } public short Mul(short a, sh

是否可以为任何类型的整数大小设置模板方法

为了举例说明,想象一下这个非常简单的例子(在我的问题中,方法的主体并不重要):

现在,我想要支持任何类型整数的相同方法(当然不包括BigInteger)。我必须写出所有变体:

public long Mul(long a, long b)    {
    return a*b;
}
public ulong Mul(ulong a, ulong b)    {
    return a*b;
}
public short Mul(short a, short b)    {
    return a*b;
}
public ushort Mul(ushort a, ushort b)    {
    return a*b;
}
public byte Mul(byte a, byte b)    {
    return a*b;
}
虽然这个例子非常简单,实际上也不存在复制的问题,但如果我有更复杂的算法(复制所有整数类型):

我的结论是这是不可能的。。。这就是MS必须实现所有重载的原因

有没有人有任何设计通用整数方法而不必复制逻辑的技巧?

考虑一下DLR:

    static void Main(string[] args)
    {
        int i = Mul(2, 4);
        Console.WriteLine(i);
        Console.Read();
    }

    static dynamic Mul(dynamic x, dynamic y)
    {
        return x * y;
    }
性能有待确定(我希望它比直接重载慢),但可读性要好得多。如果您提供的类型没有实现所需的运算符,或者不同的类型导致值被截断,那么可能会有点麻烦

根据评论更新:
如果性能如此关键,那么听起来您已经在复制/可读性和追求的性能之间进行了权衡。编码并继续前进。一些额外代码的任何维护问题都可能与性能本身的维护相形见绌。

好吧,您可以在构建过程中使用,例如,生成重复的代码。

没有干净的高性能解决方案。我能想到的选择是:

  • 手动复制代码(快速和冗余)
  • 使用代码生成器自动复制代码(速度快但有点难看)。一个.net数字图书馆就是这样的,但我不记得它的名字了
  • 使用某种形式的间接寻址,例如MiscUtil的
    运算符
    类或DLR(慢速)
  • 算术助手结构。我不确定表演有多好,但你可以试试
  • 表示运算符的通用方法: 这是我的第一个想法。问题是如何实施它们。MiscUtil通过调用存储在静态字段中的委托来实现这一点

    static Func<T,T,T> _multiply;
    public static T Multiply(T n1,T n2)
    {
      return _multiply(n1, n2);
    }
    
    JIT编译器足够聪明,可以在必须采取的情况下实现这些
    中的哪一种,并将它们删除。虽然这提高了性能,但却增加了方法的IL表示。JIT编译器现在还不够聪明,无法内联这些方法,因为它们的IL表示很长,而内联启发式只查看方法的IL长度,而不是机器代码长度。我不记得这些投射是否会导致拳击,或者抖动是否足够聪明,可以优化它。不过,缺少内联的代价太高了

    4)工作原理: 首先创建一个包含所需基本操作(算术运算符,…)的接口:

    interface-IArithmetic
    {
    T乘(T n1,T n2);
    }
    
    使用结构为您需要的每种类型实现它:

    public struct int32算术:IArithmetic
    {
    Int32乘法(Int32 n1,Int32 n2)
    {
    返回n1*n2;
    }
    }
    
    然后将大部分实际代码设置为通用代码,并传入算术助手:

    internal T MyOperation<T,TArithmetic>(T n1, T n2)
      where TArithmetic:struct,IArithmetic<T>
    {
       return default(TArithmetic).Multiply(n1,n2);
    }
    
    内部T操作(T n1,T n2)
    其中TArithmetic:struct,IArithmetic
    {
    返回默认值(TArithmetic).Multiply(n1,n2);
    }
    
    如果您想为多种类型创建一个干净的接口,请创建一个瘦重载包装器,转发到泛型方法:

    public Int32 MyOperation(Int32 n1,Int32 n2)
    {
      return MyOperation<Int32,Int32Arithmetic>(n1, n2);
    }
    
    public Int32 MyOperation(Int32 n1、Int32 n2)
    {
    返回操作(n1,n2);
    }
    
    这可能很快,因为泛型会针对每种值类型进行专门化。它不使用间接方法,并且IL中的方法体不会太长,因此内联是可能的。但我自己还没有尝试过。

    publictmul(ta,tb){
    
    public T Mul<T>(T a, T b){
        dynamic x = a;
        dynamic y = b;
        return (T)x*y;
    }
    
    动态x=a; 动态y=b; 返回(T)x*y; }
    我曾经尝试过使用CodeDom实现类似的功能,以便在运行时生成程序集并动态加载它。这很好,但有一些局限性。例如,您的环境可能不允许您动态编译程序集,这是一个大问题:性能。尽管“calculator”类只生成一次,但调用虚拟方法的开销实际上使计算所需的时间增加了一倍

    您可以尝试一下它在您的环境中的性能,我只是布置了类(因为这是很久以前的事了,我再也没有代码了)

    接口计算器{
    T加(T左,T右);
    T乘(T左,T右);
    }
    内部静态类计算器{
    静态计算器实例;
    静态计算器(){
    类型=类型(T);
    //1.使用CodeDom设计一个类,该类使用
    //内置+,-,*,/运算符
    //2.在内存中编译程序集
    //3.加载程序集并创建ICalculator类的实例
    类型concreteType=GetTypeFromDynamicsSembly();//从程序集获取此值。
    instance=Activator.CreateInstance(concreteType)作为iCalCalculator;
    }
    公共静态T添加(T左,T右){
    返回实例.Add(左、右);
    }
    }
    类MyClassUsingGenericMathType{
    T总和(参数T[]值){
    T总和=默认值(T);
    foreach(值中的T值){
    总和=计算器。加(总和,值);
    }
    回报金额;
    }
    }
    
    其思想是在第一次使用实现时动态构建它(然后调用静态构造函数),然后计算器方法直接调用所使用的数值类型的相应运算符。正如我所说的,我记得每次执行操作时都会增加开销,但我从未分析过使用某些编译器属性是否有可能加快进程

    另一件事:使用未实现相应运算符的类型将导致运行时异常,而不是编译错误。所以是
    static Func<T,T,T> _multiply;
    public static T Multiply(T n1,T n2)
    {
      return _multiply(n1, n2);
    }
    
    public static T Multiply(T n1,T n2)
    {
      if(typeof(T)==typeof(int))
        return (T)(object)((int)(object)n1*(int)(object)n2);
      ...
      return _multiply(n1, n2);
    }
    
    interface IArithmetic<T>
    {
       T Multiply(T n1,T n2);
    }
    
    public struct Int32Arithmetic:IArithmetic<Int32>
    {
       Int32 Multiply(Int32 n1,Int32 n2)
       {
         return n1*n2;
       }
    }
    
    internal T MyOperation<T,TArithmetic>(T n1, T n2)
      where TArithmetic:struct,IArithmetic<T>
    {
       return default(TArithmetic).Multiply(n1,n2);
    }
    
    public Int32 MyOperation(Int32 n1,Int32 n2)
    {
      return MyOperation<Int32,Int32Arithmetic>(n1, n2);
    }
    
    public T Mul<T>(T a, T b){
        dynamic x = a;
        dynamic y = b;
        return (T)x*y;
    }
    
    interface ICalculator<T> {
        T Add(T left, T right);
        T Multiply(T left, T right);
    }
    
    internal static class Calculator<T> {
         static ICalculator<T> instance;
         static Calculator() { 
              Type type = typeof(T);
              // 1. Use CodeDom to design a class that implements ICalculator<T> using the
              // builtin +,-,*,/ operators
              // 2. Compile assembly in memory
              // 3. Load assembly and create an instance of the ICalculator<T> class
              Type concreteType = GetTypeFromDynamicAssembly(); // Get this from the assembly.
              instance = Activator.CreateInstance(concreteType) as ICalculator<T>;
         }
    
         public static T Add(T left, T right) {
              return instance.Add(left, right);
         }
    }
    
    class MyClassUsingGenericMathType<T> {
        T Sum(params T[] values) {
            T sum = default(T);
            foreach (T value in values) {
                sum = Calculator<T>.Add(sum, value);
            }
    
            return sum;
        }
    }