4

次のクラスを作成して、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
}

どうすればそれを達成できますか?

test<T>各型のメソッドを明示的に定義すると、そのクラスでも各型のメソッドを明示的に定義しないと、別のジェネリック型からそのクラスを使用できません。

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
    }
}
4

2 に答える 2

3

純粋な C# を使用した私のソリューション ( ILまたはサードパーティ ライブラリなし):

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");
    }
}
于 2013-04-28T05:32:04.727 に答える
1

あなたがやろうとしていることを行うための良い方法を見つけることはできないと思います. いくつかの可能性:

  1. あなたが示すように動的に使用してください。
  2. if/else チェーンを用意するか、完全な型名をオンにして、既知の型のリストが等しいものとして識別しますT(例:if (typeof(T) == typeof(int)) add((int)a,(int)b);など)。
  3. を使用する代わりに、正しいメソッドを呼び出すクラスをnew test<int>作成します。testInt : test<int>
  4. ではなく でdynamicキャストを使用して add メソッドを呼び出します。test<T>agg<T>

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);
}

4 の例:

public class test<T>{
    public test(T a,T b){
        T c = agg.add((dynamic)a, (dynamic)b);
    }
}

ボックス化/ボックス化解除に関心があるのはなぜですか? これはパフォーマンスが非常に重要なタスクですか? もしそうなら、動的を含むものはすべて実行不可能になる可能性があります. このコードをできるだけ速く実行する必要があるかどうか確信が持てない場合は、時期尚早に最適化しないでください。現時点ではパフォーマンスのことは忘れて、できる限り最善で最も読みやすい方法で問題を解決してください。

于 2013-04-28T03:24:56.283 に答える