2012-01-12 2 views
1

ジェネリックスを使用して問題が発生しました。 (それが正しい場合)私はこれは私が算術問題を作成する例であるジェネリッククラス<T>のシナリオを解決するにはどうすればよいですか?

public interface IProblem<T> 
{ 
    ushort ResultCount { get; } 
    T[] Results { get; } 

    bool IsCorrect(); 
} 

public abstract class ProblemBase<T> : IProblem<T> 
{ 
    private T[] _results; 
    private ushort? _resultCount; 

    public ushort ResultCount 
    { 
     get 
     { 
      if (_resultCount == null) throw new ArgumentNullException("_resultCount"); 
      return (ushort)_resultCount; 
     } 
     protected set 
     { 
      if (_resultCount != value) 
       _resultCount = value; 
     } 
    } 

    public T[] Results 
    { 
     get 
     { 
      if (_results == null) 
       _results = new T[ResultCount]; 

      return _results; 
     } 
    } 

    public abstract bool IsCorrect(); 
} 

各問題結果(回答)を有するIProblemと呼ばれるインターフェース、および結果を作成してい、ProblemAと呼ばれます。配列のデータ型は

public class ProblemA: ProblemBase<decimal> 
{ 
    private decimal _number1; 
    private decimal _number2; 
    private Operators _operator; 

    public decimal Number1 
    { 
     get { return _number1; } 
     set { _number1 = value; } 
    } 

    public decimal Number2 
    { 
     get { return _number2; } 
     set { _number2 = value; } 
    } 

    public Operators Operator 
    { 
     get { return _operator; } 
     set { _operator = value; } 
    } 

    public decimal Result 
    { 
     get { return Results[0]; } 
     set { Results[0] = value; } 
    } 

    public ProblemA() 
    { 
     this.ResultCount = 1; 
    } 

    public override bool IsCorrect() 
    { 
     bool result; 

     switch (_operator) 
     { 
      case Operators.Addition: 
       result = this.Result == (this.Number1 + this.Number2); 
       break; 
      case Operators.Subtract: 
       result = this.Result == (this.Number1 - this.Number2); 
       break; 
      case Operators.Multiplication: 
       result = this.Result == (this.Number1 * this.Number2); 
       break; 
      case Operators.Division: 
       result = this.Result == (this.Number1/this.Number2); 
       break; 
      default: 
       throw new ArgumentException("_operator"); 
     } 

     return result; 
    } 
} 

(anothers問題は多分string、またはintを持っているかもしれません)小数でなければなりませんのでTdecimalである私は、MVVMを使用していますので、私はProblemBase<T>などを含む各問題のためのViewModelを持っているしたいのですがプロパティ、しかしそれは一般的な、私はそれが問題のようになる場合は、IProblemViewModel一般的に入れていると思います。

public interface IProblemViewModel : IViewModel 
{ 
    ProblemBase<T> Problem { get; set; } 
} 

私はObservableCollection<IProblemViewModel>を使用するには、後に計画ので、これを言ったので、私は、私はIProblemViewModelまたはIProblemViewModel<T>を書く場合は問題はありませんかはわかりません。 ありがとうございます。

+1

それはそれを上書きしないために他の場所でいくつかのバグを待っNotImplementedException()を投げるの周りところで、実装を放置しないでください。 'パブリック抽象ブールIsCorrect()を実行します;'とabstactクラスが行くように、あなたは限りインターフェースを果たすが、それはコンパイルされませんオーバーライドするために失敗した任意の具体的な派生クラス。 –

+0

@ジョンハンナは、チップジョンのおかげで、私はまだそれについて学んでいる!私は心の中で助言のための –

答えて

2

おそらく私はこれを完全には理解していないかもしれませんが、これはあなたの後のものですか?

ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>> 
    { 
     new ProblemViewModel<DerivedResult>(), 
     new ProblemViewModel<OtherResult>() 
    }; 

これは、汎用引数を共変(covariant)として宣言することで実現できます。

また

ObservableCollection<IProblem<BaseType>> 

にコレクションを変更し、ちょうどそれが特定の結果のチェーンを受け入れる可能性があります。この例では、DerivedResultおよびOtherResultは、コレクションに収まるようにBaseTypeから継承する必要があります。

大きな注意点は、プリミティブ型がこの階層にどのような形でも適合しないことです。あなたはIProblem<IntResult>にそれらをラップする必要があります。

もちろん、タイプごとに1つの値タイプを実装するのではなく、任意の値タイプをボックス化するBoxerなど、単純なキャリアを実装することもできます。

最後に1つ注意してください:共変タイプに 'set'プロパティを設定することはできません。したがって、IProblemViewModelgetのみをサポートできます。

完了し、コンパイル例:

class Program 
{ 

    public interface IProblem<out T> 
    { 
     ushort ResultCount { get; } 
     T[] Results { get; } 

     bool IsCorrect(); 
    } 

    public class ProblemBase<T> : IProblem<T> 
    { 
     private T[] _results; 
     private ushort? _resultCount; 

     public ushort ResultCount 
     { 
      get 
      { 
       if (_resultCount == null) throw new ArgumentNullException("_resultCount"); 
       return (ushort)_resultCount; 
      } 
      protected set 
      { 
       if (_resultCount != value) 
        _resultCount = value; 
      } 
     } 

     public T[] Results 
     { 
      get 
      { 
       if (_results == null) 
        _results = new T[ResultCount]; 

       return _results; 
      } 
     } 

     public bool IsCorrect() 
     { 
      return true; 
     } 
    } 

    public interface IProblemViewModel<out T> 
    { 
     IProblem<T> Problem { get; } 
    } 

    public class BaseResult 
    { 

    } 

    public class DerivedResult : BaseResult 
    { 

    } 

    public class OtherResult : BaseResult 
    { 

    } 

    public class ProblemViewModel<T> : IProblemViewModel<T> 
    { 

     public IProblem<T> Problem 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 
    } 


    static void Main(string[] args) 
    { 
     ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>> 
     { 
      new ProblemViewModel<DerivedResult>(), 
      new ProblemViewModel<OtherResult>() 
      //, new ProblemViewModel<int>() // This is not possible, does not compile. 
     }; 
    } 
} 
0

あなたのビューモデルインターフェイスは、次のように定義することができます。

public interface IProblemViewModel<T> : IViewModel 
{ 
    //No reason to use the base here instead of the interface 
    IProblem<T> Problem { get; set; } 
} 

私はあなたがWPFやSilverlightのインターフェイスに問題を結合することを計画しているかどうかわからないんだけど、あなたがある場合はそのことを確認してください問題また、INotifyPropertyChangedを実装します。 INotifyPropertyChangedを実装していないオブジェクトの非依存プロパティへのバインドは、オブジェクトが決して解放されないメモリリークを引き起こします。あなたはここに漏れの詳細を見つけることができます:http://support.microsoft.com/kb/938416

EDIT:コメントへの回答を追加しました。

あなたは<T>複数のタイプを表示する場合はIProblemViewModel<T>を持つことのObservableCollectionにそれを使用して、あなたを停止することが正しいです。しかし、バインドしているときは、バインドするときにオブジェクトの種類が何であるかは問題にならないので、コレクションをObservableCollection<IViewModel>にするのはなぜですか?

+0

感謝を負担します、私は本当にその問題についての考えを持っていません。ちなみに、私がメモを追加するのを忘れ:私はこれができないと思い、のObservableCollection を持っていることを計画します。 –

+0

ObservableCollectionの問題を解決するために私の答えを更新しました。 –

+0

ええ、私はそれについて考えたが、私はこれを行うことができますね。.. パブリックインターフェイスIProblemViewModel :IProblemViewModel { IProblem 問題{取得します。セット; } } パブリックインターフェイスIProblemViewModel:IViewModel {} ObservableCollection 、あなたはどう思いますか? –

関連する問題