2012-04-03 10 views
2

私は、以下に示すようなジェネリック型のプロパティを持つクラスを持っています。明示的な変換なしで数値を処理する一般的な方法

public class EqualFilter <T> : Filter { 
     private T _value; 
     public override T Value { 
     get { 
      return _value; 
     } 
     set { 
      if (!EqualityComparer<T>.Default.Equals(_value, value)) { 
       _value = value; 
       RaiseFilteringChanged(); 
      } 
     } 
    } 
    ..... 
} 

(...短い、int型、float型)Tは、任意の数の可能なタイプ今、私は上記のセッターに渡される必要がある「文字列」を持つクライアントクラスを持っています。上記のセッターで値を設定する時点で、タイプTは既に実行時に決定されており、クライアントでタイプTとしてそのタイプを保持できます。クライアントプログラムでEqualFilterによって識別されるように、文字列を適切な型に変換することは可能ですか?これがうまくいかないようなもの

Type T = filter.getFilterType(); 
filter.Value = (T) myTextBox.Text; 

以下のコードは機能しますが、数字でもよいすべての型に対してif-elseが関係します。

Type T = filter.getFilterType(); 
if (T == typeof(int)) { 
    filter.Value = Int32.Parse(myTextBox.Text); 
} else if() { 
.... 
} 

簡潔に言えば、問題をより良い方法で解決する方法がわかりません。

+0

「T」に型制約を付けることはできませんか? http://msdn.microsoft.com/en-us/library/d5x73970.aspx – Bazzz

+0

私はあなたから提供された提案にどのようにアプローチするのか分かりません。あなたは私にいくつかの詳細を教えてください。また、Tにクラス制約を置くと、フィルタ値が比較的多数の行に対して値の比較に使用されるため、パフォーマンスが低下するでしょう。 – Jatin

+2

これは 'T 'が受け入れる型の単なる制限です。現在のコードで 'T'をANY型にすることができます。これを特定のインターフェースに限定し、受け入れられたすべての型にこのインターフェースを実装させることができます。プリミティブ型では少し不安ですが、 'IComparable'は' T:IComparable'のように良いでしょう。比較の前に実際の型に 'T'をキャストする必要はありません。なぜなら、あなたのメソッドで終わるすべての' T'が 'IComparable'なので、' IComparable'に安全にキャストし、 'Compare'メソッドを使うことができるからです。 '((IComparable)T).Compare();'ではなく、あなたのすべてのキャストではありません。 – Bazzz

答えて

2

あなたはデータバインディングに似た何かをやっているようですね。

public class EqualFilter<T> : Filter where T : IConvertible { 

    // ... omitted Value property code ... 

    public void SetValue(string value) 
    { 
     Value = (T)Convert.ChangeType(value, typeof(T)); 
    } 

    // ... 
} 

ジェネリック型制約が許すもののみのタイプを:あなたが興味を持っているすべての文字列で動作している場合、あなたはIConvertibleにジェネリック型を制約し、そのような特別なセッターメソッドからConvert.ChangeTypeメソッドを呼び出して検討するかもしれませんConvert.ChangeTypeが操作できます。積分型と浮動小数点型以外にも、string,decimalおよびDateTimeの型の使用が許可されています。 のタイプは、丸めと浮動小数点表現のエラーがある可能性があるので、doubleタイプで作業する場合は必ずしも正確ではないことに注意してください。また、これをより堅牢にするためにキャッチしたいかもしれない他の例外があるかもしれません(例えば、FormatExceptionOverflowException)。

void Main() 
{ 
    var a = new EqualFilter<int> { Value = 10 }; 
    var b = new EqualFilter<double> { Value = 20 }; 
    b.Value = Math.PI; // RaiseFilteringChanged called - no surprise 
    b.SetValue(Math.PI.ToString()); // RaiseFilteringChanged called - surprised? 
    Console.WriteLine(b.Value); 
    b.SetValue("25"); 
    Console.WriteLine(b.Value); 
    var c = new EqualFilter<DateTime> { Value = DateTime.Today }; 
    Console.WriteLine(c.Value); 
    c.SetValue("12/23/2011"); 
    Console.WriteLine(c.Value); 

    // compiler error object isn't an IConvertible: 
    // var illegal = new EqualFilter<object>(); 
} 

この場合、big switch文は、ChangeTypeメソッドのフレームワークによって処理されます。

編集:

3.14159265358979

: は、上記のコード(すなわち、上書きとベースクラスの使用コメントアウトを有する)の私のバージョンからConsole.WriteLine出力を加算4/10/2012 12:00:00 AM

2011/12/23 12:00:00 AM

+0

"Value =(T)Convert.ChangeType(value、typeof(T));"の無効なキャスト例外が発生しました。 Convert.ChangeType()を使用して文字列をnumeric(int、float、...)に変換することはできません。 – Jatin

+0

あなたが使用しているコードを投稿できますか?私がここに投稿したバージョンでは、基本クラスを持たずに、コンパイルしてテストできるようにコメントアウトした部分を復元しました。それは私のために働いた - 無効なキャスト - 私はあなたがコードの残りの部分を投稿する場合、明らかになる可能性のある何か他のものがあるかどうか疑問に思っています。 – devgeezer

+0

私の以前のコメントについては申し訳ありません。あなたのコードはうまくいくので、私は答えとしてマークしています。しかし、あなたが別の関連する問題で私を助けることができれば。私はEqualFilter を使用して、モデルクラスプロパティの型に基づいてすべての数値型に対してEqualFilter 、EqualFilter などの型をインスタンス化しています。このインスタンス化を一般化することは可能ですか?すべての数値型に対してEqualFilter <>インスタンス化行が1つしかありません。同様にFilter(EqualFilter <>の基本クラス)をEqualFilterにキャストすると、各タイプ(int、doubleなど)に対してelseを持つ代わりに、コード内で1回だけ行います。 – Jatin

1

次の操作を試みることができる:

filter.Value = Convert.ChangeType(myTextBox.Text, filter.getFilterType()); 

変換はいえ定義されていない場合、これは動作しません。

編集:

私はあなたのValueプロパティがジェネリックた気づきませんでした。

public object UnsafeValue 
{ 
    set 
    { 
     Value = (T)value; 
    } 
} 

をし、そのプロパティにConvert.ChangeTypeの結果を割り当てる: あなたはこのような何かによって、あなたのフィルタオブジェクトを拡張することができ、この作業を行います。

フィルタクラスを変更しないすべてのアプローチでは、コール階層またはリフレクションでより多くのジェネリックが必要になります。

+0

@ConvertTypeはオブジェクトを返すので、Tにキャストする必要があり、コンパイラはそれを許可しません - "型または名前空間が見つかりません"。 – Jatin

+0

@Nirvan:私の編集を参照してください。 – Nuffin

+0

最初は有望な解決策のように見えましたが、値=(T)値はキャストに失敗し、実行時例外が発生します。私はアプローチを再考しなければならないと思います。おそらく、@Bazzがコメントしたことに従って、その動作を見てください。私が取り組んできた言語の1つでは、すべての数値型を包含する基本クラスNumberを持っています。それを使用して、私がいる状況を処理するのは非常に簡単でした。しかし、C#には他の言語にはない多くの機能があり、それにはかなり満足しています。 – Jatin

0

は、あなたがこのような具体的なsetterメソッドを作成する考えた:

public void setValue(object o){ 
    if (typeof(o) == typeof(Value)) { 
     Value = (typeof(Value))o; 
    } 
} 
+0

それがうまくいけば、OPは最初に尋ねなかったでしょう。 – Nuffin

関連する問題