2012-01-12 28 views
1

我有使用泛型的問題。我創建一個名爲IProblem的接口,其中每個問題有結果(答案)和結果(如果它是正確的)如何解決通用類<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(); 
} 

這是我創造的算術問題的例子,叫做ProblemATdecimal因爲數組類型應是小數(anothers問題也許可能有string,或int

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

我使用MVVM,所以我想有一個視圖模型爲每個問題,其中包含ProblemBase<T>爲財產,但它是如何通用的,我想這將是一個問題,如果把IProblemViewModel作爲通用。

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

我這樣說是因爲後來計劃使用ObservableCollection<IProblemViewModel>,所以我不知道如果我寫IProblemViewModelIProblemViewModel<T>沒有任何問題。 在此先感謝。

+1

順便說一句,不留一個實現各地拋出NotImplementedException()等其他地方的一些bug失敗來覆蓋它。做'public abstract bool IsCorrect();'並且儘可能完成接口,但是任何具體的派生類都不能覆蓋它。 – 2012-01-13 03:10:41

+0

@JonHanna感謝Jon的提示,我還在學習它!我會記住 – 2012-01-13 03:17:57

回答

2

也許我還沒有完全理解這個,但是這是你在追求什麼?

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

這可以通過將通用參數聲明爲協變來實現。

你也可以改變集合

ObservableCollection<IProblem<BaseType>> 

,只是有它接受一個特定的結果鏈。在此示例中,DerivedResult和OtherResult必須從BaseType繼承以適應集合。

需要注意的是,原始類型無論如何都不適合這個層次結構。你將不得不把它們包裝在IProblem<IntResult>等等。

當然,你可以實現一個簡單的載體,例如Boxer,它可以包裝任何值類型,而不是爲每種類型實現一個。

最後一個警告:在協變類型上不可能有'set'屬性,所以IProblemViewModel只能支持get

一個完整的,可編譯例子:

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

編輯:添加回複評論。

你是正確的,你在一個ObservableCollection使用它,如果你打算顯示多個類型的<T>具有IProblemViewModel<T>將停止。然而,自從綁定時,綁定到對象類型時,綁定到對象的類型並不重要,爲什麼不把這個集合設爲ObservableCollection<IViewModel>

+0

感謝您的意見,我真的不知道這個問題。順便說一句,我忘了添加一個註釋:我打算有一個ObservableCollection ,我想這是不可能的。 – 2012-01-13 03:06:17

+0

我已更新我的答案,嘗試和幫助ObservableCollection問題。 – 2012-01-13 03:17:39

+0

是啊,我想過這個問題,我想我可以做到這一點.. 公共接口IProblemViewModel :IProblemViewModel { IProblem 問題{獲得;組; } } public interface IProblemViewModel:IViewModel {} 爲此:ObservableCollection ,您怎麼看? – 2012-01-13 03:27:51

相關問題