Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中使用泛型时如何避免装箱/取消装箱?_C#_C# 4.0_Generics_Dynamic_Boxing - Fatal编程技术网

在C#中使用泛型时如何避免装箱/取消装箱?

在C#中使用泛型时如何避免装箱/取消装箱?,c#,c#-4.0,generics,dynamic,boxing,C#,C# 4.0,Generics,Dynamic,Boxing,我想让以下类与int、double和其他加法类型一起工作,而不需要装箱/取消装箱的运行时开销,但可以从另一个泛型类型重用: public class agg<T>{ public static T add(T a,T b){return a+b;} // compile error: Operator '+' cannot be applied to operands of type 'T' and 'T' public static T add(T a,T b){r

我想让以下类与
int
double
和其他加法类型一起工作,而不需要装箱/取消装箱的运行时开销,但可以从另一个泛型类型重用:

public class agg<T>{
    public static T add(T a,T b){return a+b;} // compile error: Operator '+' cannot be applied to operands of type 'T' and 'T'
    public static T add(T a,T b){return (dynamic)a+b;} // compiles, but involves boxing and unboxing at run-time
}
公共类agg{
公共静态T add(ta,tb){返回a+b;}//编译错误:运算符“+”不能应用于“T”和“T”类型的操作数
公共静态T add(ta,tb){return(dynamic)a+b;}//编译,但在运行时涉及装箱和取消装箱
}
我怎样才能做到这一点

如果我为每个类型显式定义了方法,那么如果不在该类中为每个类型显式定义方法,我就无法从另一个泛型类型
test
使用该类:

public class agg<T>{
    //public static T add(T a,T b){return a+b;} // compile error: Operator '+' cannot be applied to operands of type 'T' and 'T'
    //public static T add(T a,T b){return (dynamic)a+b;} // compiles, but involves boxing and unboxing at run-time
    public static int add(int a,int b){return a+b;} // won't be matched by test agg<T>.add(a,b) invokation
}
public class test<T>{
    public test(T a,T b){
        var c=agg<T>.add(a,b); //compile error: The best overloaded method match for 'agg<T>.add(int, int)' has some invalid arguments
    }
}
公共类agg{
//公共静态T add(ta,tb){返回a+b;}//编译错误:运算符“+”不能应用于“T”和“T”类型的操作数
//公共静态T add(ta,tb){return(dynamic)a+b;}//编译,但在运行时涉及装箱和取消装箱
公共静态intadd(inta,intb){returna+b;}//将不会被test agg.add(a,b)调用匹配
}
公开课考试{
公共测试(TA、TB){
var c=agg.add(a,b);//编译错误:“agg.add(int,int)”的最佳重载方法匹配有一些无效参数
}
}

我认为你不会找到一个好方法来做你想做的事情。一些可能性:

  • 使用动态显示方式
  • 有一个if/else链,或打开完整的类型名,以识别已知类型列表等于
    T
    (例如
    if(typeof(T)==typeof(int))add((int)a,(int)b);
    等)
  • 不要使用
    newtest
    ,而是创建一个调用正确方法的
    testInt:test
  • test
    中使用
    dynamic
    casting调用add方法,而不是在
    agg
    中调用
  • 示例3:

    public static class agg{
        public static int add(int a,int b){return a+b;}
        public static byte add(byte a,byte b){return (byte)(a+b);}
        public static decimal add(decimal a,decimal b){return a+b;}
        // etc
    }
    public class testInt:test<int>
    {
        public testInt(int a, int b) : base(a, b) { }
        protected override int add(int a, int b)
        {
            return agg.add(a, b);
        }
    }
    public abstract class test<T>{
        public test(T a,T b){
            T c = add(a, b);
        }
        protected abstract T add(T a, T b);
    }
    
    公共静态类agg{
    公共静态intadd(inta,intb){返回a+b;}
    公共静态字节加法(字节a,字节b){返回(字节)(a+b);}
    公共静态十进制加法(十进制a,十进制b){返回a+b;}
    //等
    }
    公共类测试:测试
    {
    公共测试(inta,intb):基(a,b){}
    受保护的覆盖整数添加(整数a、整数b)
    {
    返回加总(a、b);
    }
    }
    公共抽象类测试{
    公共测试(TA、TB){
    tc=添加(a,b);
    }
    受保护的摘要T添加(T a,T b);
    }
    
    示例4:

    public class test<T>{
        public test(T a,T b){
            T c = agg.add((dynamic)a, (dynamic)b);
        }
    }
    
    公共类测试{
    公共测试(TA、TB){
    tc=agg.add((动态)a,(动态)b);
    }
    }
    
    你为什么关心装箱/拆箱?这是一项对性能高度敏感的任务吗?如果是这样,任何涉及动态的事情都可能是不可行的。如果您不确定此代码是否需要尽可能快地运行,请不要过早地进行优化:暂时忘记性能问题,并以您能用的最好、最可读的方式解决问题。

    我的解决方案使用纯C(否或):

    内部类agginit{internal static bool start=false;}
    公共类agg{
    //公共静态T add(ta,tb){返回a+b;}//编译错误:运算符“+”不能应用于“T”和“T”类型的操作数
    //公共静态T add(ta,tb){return(dynamic)a+b;}//编译,但在运行时涉及装箱和取消装箱
    //公共静态intadd(inta,intb){returna+b;}//将不会被test agg.add(a,b)调用匹配
    公共静态T add(ta,tb){return_add(a,b);}
    静态函数_add=null;
    公共静态void setAdd(Func f){if(_add==null)_add=f;else抛出新异常(“不能两次初始化”);}
    静态agg(){
    如果(!agginit.started){//以防止递归操作
    agginit.started=true;
    加总=(a,b)=>a+b;
    加总=(a,b)=>a+b;
    //下面我们初始化所有其他可能使用的加法类型只是为了好玩,如果这里没有列出类型,则不支持它
    加总=(a,b)=>a+b;
    agg._add=(a,b)=>{return(byte)(a+b);};//脏向下转换,需要使用返回类型泛型参数进行增强
    加总=(a,b)=>a+b;
    加总=(a,b)=>a+b;
    agg._add=(a,b)=>{var ret=new StringBuilder();ret.Append(a.ToString());ret.Append(b.ToString());return ret;};
    加总=(a,b)=>a.Concat(b);
    agg._add=(a,b)=>{var ret=new HashSet(a);ret.UnionWith(b);return ret;};
    agg._add=(a,b)=>{var ret=new SortedSet(a);ret.UnionWith(b);ret ret;};
    agg._add=(a,b)=>{var ret=新字节[a.Length+b.Length];Buffer.BlockCopy(a,0,ret,0,a.Length);Buffer.BlockCopy(b,0,ret,a.Length,b.Length);ret;};
    agg._add=(a,b)=>{var ret=new System.IO.MemoryStream(新字节[a.Length+b.Length]);a.WriteTo(ret);b.WriteTo(ret);ret;};
    }
    }
    }
    公开课考试{
    公共物品;
    公共测试(TA、TB){
    res=加总(a,b);
    }
    }
    公共A类{
    公共INTZ;
    静态A(){
    agg.setAdd((a,b)=>newa{z=a.z+b.z});//任何类都可以定义自己的add实现
    }
    公开无效测试(){
    var t1=agg.add(新的A{z=1},新的A{z=2});
    如果(t1.z!=3)抛出新异常(“测试失败”);
    var t2=新测试(新A{z=1},新A{z=2});
    如果(t2.res.z!=3)抛出新异常(“测试失败”);
    }
    }
    
    如果它是double,那么为什么要使用泛型呢?您可以有两个Add方法。double Add(double a,double b)和int Add(int a,int b)。查看与运算符讨论这个问题的内容。@Alexei:我在这里看到4件事:1)可下载源代码的引用,2)动态,3)ICalc,4)IL#2和#3不是很好,#4如果有效的话会很有趣,但我想知道更多关于纯C的解决方案#1-可下载的源代码做了很多事情,我想要一些简单的例子。我找到了比你提到的4个更好的方法(见我的答案),它不涉及强制转换、为每种模板类型定义单独的类,或者为每种类型定义if语句。在某些应用领域(例如嵌入式系统
    internal class agginit{internal static bool started=false;}
    public class agg<T>{
        //public static T add(T a,T b){return a+b;} // compile error: Operator '+' cannot be applied to operands of type 'T' and 'T'
        //public static T add(T a,T b){return (dynamic)a+b;} // compiles, but involves boxing and unboxing at run-time
        //public static int add(int a,int b){return a+b;} // won't be matched by test agg<T>.add(a,b) invokation
        public static T add(T a,T b){return _add(a,b);}
        static Func<T,T,T> _add=null;
        public static void setAdd(Func<T,T,T> f){if(_add==null)_add=f;else throw new Exception("Can't init twice");}
        static agg(){
            if(!agginit.started){ // to prevent recursive actions
                agginit.started=true;
                agg<int>._add=(a,b)=>a+b;
                agg<double>._add=(a,b)=>a+b;
                // below we initialize all other potentially used additive types just for fun, if type is not listed here, it's not supported
                agg<string>._add=(a,b)=>a+b;
                agg<byte>._add=(a,b)=>{return (byte)(a+b);}; // dirty down-cast, needs to be enhanced with return type generic parameter
                agg<long>._add=(a,b)=>a+b;
                agg<System.Numerics.BigInteger>._add=(a,b)=>a+b;
                agg<StringBuilder>._add=(a,b)=>{var ret=new StringBuilder();ret.Append(a.ToString());ret.Append(b.ToString());return ret;};
                agg<IEnumerable<T>>._add=(a,b)=>a.Concat(b);
                agg<HashSet<T>>._add=(a,b)=>{var ret=new HashSet<T>(a);ret.UnionWith(b);return ret;};
                agg<SortedSet<T>>._add=(a,b)=>{var ret=new SortedSet<T>(a);ret.UnionWith(b);return ret;};
                agg<byte[]>._add=(a,b)=>{var ret=new byte[a.Length+b.Length];Buffer.BlockCopy(a,0,ret,0,a.Length);Buffer.BlockCopy(b,0,ret,a.Length,b.Length); return ret;};
                agg<System.IO.MemoryStream>._add=(a,b)=>{var ret=new System.IO.MemoryStream(new byte[a.Length+b.Length]);a.WriteTo(ret);b.WriteTo(ret);return ret;};
            }
        }
    }
    public class test<T>{
        public T res;
        public test(T a,T b){
            res=agg<T>.add(a,b);
        }
    }
    public class A{
        public int z;
        static A(){
            agg<A>.setAdd((a,b)=>new A{z=a.z+b.z}); // any class can define own add implementation
        }
        public void test(){
            var t1=agg<A>.add(new A{z=1},new A{z=2});
            if(t1.z!=3)throw new Exception("test failed");
            var t2=new test<A>(new A{z=1},new A{z=2});
            if(t2.res.z!=3)throw new Exception("test failed");
        }
    }