2012-02-18 8 views
5

可能性の重複:
C# generic constraint for only integersC#で汎用的な数値を合計するにはどうすればよいですか?

次のコードで見ることができるように、私は2つの一般的な数字の合計を計算する必要があります。

演算子「+」型のオペランドに適用することができない。

public class NumberContainer<T> 
{ 
    public T ValueA { get; private set; } 
    public T ValueB { get; private set; } 
    public T Total { get { return ValueA + ValueB; } } 
} 

しかし、下にコンパイラエラーになる2つのT値の直接添加を行うことは不可能です「T」と「T」

私はどのように行うことができ、(など短い、USHORT、INT、UINT、)数を表す値、タイプよりも、何のためにTを使用しないことを考えます和?

+0

または可能性のための実装を提供する特定のクラスを派生できます:[「実数」のためのC#の一般的な制約がありますタイプ?](http://stackoverflow.com/questions/1348594/is-there-ac-sharp-generic-constraint-for-real-number-types/1348625#1348625) –

+1

質問は質問の複製として閉じられていますこの問題が何をしようとしているのではないかという、「T」に制約を課そうとしている。私はそれを再開すべきだと思う。 – dasblinkenlight

答えて

12

あなたはLINQから「小さな魔法」でそれを行うことができます。

private static readonly Func<T, T, T> adder; 
static NumberContainer() { 
    var p1 = Expression.Parameter(typeof (T)); 
    var p2 = Expression.Parameter(typeof (T)); 
    adder = (Func<T, T, T>)Expression 
     .Lambda(Expression.Add(p1, p2), p1, p2) 
     .Compile(); 
} 
public T Total { get { return adder(ValueA, ValueB); } } 

唯一の欠点NumberContainerが追加をサポートしていないタイプTでインスタンス化されている場合でも、このコードコンパイルするということです。もちろん、実行時に例外がスローされます。追加の利点は、はユーザ定義の+オペレータで動作するはずです。 LINQを使用することに加えて

1

Tの制約は構造体でなければならず、おそらくIConvertableを実装してからConvertを使用するように指定することができます。

public class NumberContainer<T> 
     where T : struct, IConvertible 
    { 
     public T ValueA { get; private set; } 
     public T ValueB { get; private set; } 
     public T Total { 
      get 
      { 
       // do type checking here, then: 

       return (T)Convert.ChangeType(
        Convert.ToDouble((object)ValueA) + 
        Convert.ToDouble((object)ValueB), typeof(T)); 
      } 
     } 
    } 

ただし、Tは、コンパイル時に整数または浮動小数点型であることを保証するためにジェネリック医薬品と方法はありません。ただし、実行時にそれを確認して例外をスローすることができます。

+0

これはうまくいきません。実際にあなたの提案はコンパイルされません。 –

+0

頭の上から外して固定しコンパイルしました。それがうまくいかない理由についてさらに詳しく説明したいのであれば、それはもっと役立つでしょう。 – HackedByChinese

+0

DateTimeは構造体とIConvertibleですが、double型に変換することはできませんので、DateTimeパラメータで呼び出すときはいつでも例外がスローされます。 –

5

、あなたは.NET 4にしている場合、これはdynamicを使用して可能である:あなたのコードサンプルで

static T Add<T>(T x, T y) 
{ 
    dynamic dx = x, dy = y; 
    return dx + dy; 
} 

これは変身:このアプローチは、」doesnの

public class NumberContainer<T> where T: struct 
{ 
    public T ValueA { get; private set; } 
    public T ValueB { get; private set; } 
    public T Total { get { return ((dynamic)ValueA) + ((dynamic)ValueB); } } 
} 

安全を確保する。 T+をサポートしていないランダムな構造体である場合、例外が発生します(私は思う)。

+0

ダイナミックの恐ろしい使い方は、特に演算子が仮想ではないと考えている...私はそれが "うまくいく"と思っています。 (私は好ましい構造型も持っています*: - /) –

+0

@pst - 同意しましたが、うまくいきます。私はポイントを理解します。 –

1

あなただけの抽象基底クラスとしてこれを扱い、Tの値を指定し、トータル

public abstract class NumberContainer<T> 
    where T: struct 
{ 
    public T ValueA { get; private set; } 
    public T ValueB { get; private set; } 
    public abstract T Total(); 
} 

public class IntContainer : NumberContainer<int> 
{ 
    public override int Total() 
    { 
     return ValueA + ValueB; 
    } 
} 
+1

'int'を' T'に変換できれば問題ありません。あなたのコードはコンパイルされません。 –

+0

愚かな私。ダイナミクスとリンクを使用したいくつかのソリューションが存在するため、答えが更新されました。 –