2009-08-29 7 views
0

画面に物を表示するライブラリを作成しているので、IDisplayableインターフェイスを作成するとします。このインターフェイスは、オブジェクトからコントロールを作成する1つのメソッドを持っています:displayable.GetControl()いくつかの型パラメータに対してのみ機能するメソッドを持つ汎用クラス

表示できる独自のリストタイプを作成する場合は、MyList<T>です。このリストは、TIDisplayableの場合にのみ表示されるので、TがIDisplayableを実装する必要があることをMyListクラスで尋ねることができます。しかし、TがIDisplayableでないとき(そして結果としてこのリストが表示されないとき)、このリストタイプをいくつかの場所で使いたいと思う。したがって、TがIDisplayableを実装する場合、MyListはIDisplayableを実装していると言えるでしょうか? MyList<T>はIDisplayableを常に実装していますが、TがIDisplayableでない場合はGetControl()を呼び出そうとすると実行時に例外がスローされますが、静的な型の安全な方法があるかどうかを知りたいと思います。これはできますか?あるいは間違った解決策を見ていますか?

編集:

私がこれまでMYLISTがあまりにも多くの責任を持っていることの提案に同意します。私の元の考えはMyDisplayableList<T> : MyList<T> (where T : IDisplayable)を作成することでした。

このアプローチの問題は、MyListを取得してMyListを返すメソッドが多数あることです(たとえば、LinqのSelectのようなメソッド)。 MyDisplayableListでselectを使用すると、MyListが返され、MyListであっても表示できません。C#でこの問題を処理する型セーフな方法はありますか?

+1

あなたはまた、非表示のためマイリストを使用したくない理由クラス? MyList にはあまりにも多くのことをやってほしいと思っているようですが、その理由がなくては分かりません。 –

答えて

5

シンプルです。タイプがIDisplayableであることを確認してください。そうでない場合は、InvalidOperationExceptionを投げる:

if (!typeof(IDisplayable).IsAssignableFrom(typeof(T))) 
    throw new InvalidOperationException(); 

それとも、Tのインスタンスを持っている場合は、単にそのに確認してください:

IDisplayable disp = instanceOfT as IDisplayable; 
if (disp == null) 
    throw new InvalidOperationException(); 
// do stuff with `disp`. 

あなたのデザインがが欠陥があるかもしれません。あなたは、クラスにあまりにも多くを置いて、単一責任の原則に違反しているかもしれません。最初にデザインを再確認してください。

+0

ありがとう、それは私が使用しようとしているものです。しかし、私はそれが利用可能な場合、静的型安全なアプローチを好むでしょう... – Jules

+0

(クラスのいくつかの特定のメソッドのために)静的にそれを強制する方法はありません。型制約は型レベルで強制されます。 –

8

あなたはそれを記述することはできません。

public class MyList<T> : IList<T> 
{ 
    ... 
} 

public class MyDisplayableList<T> : MyList<T> where T : IDisplayable 
{ 
    ... 
} 
+0

ああありがとう、私の最初のアイデアでしたが、私は十分にあなたに話しませんでした。このアプローチの問題は、MyList を取得し、MyList を返すメソッドがたくさんあることです(LinqでSelectなどのメソッド)。 MyDisplayableListでselectを使用すると、MyListが返され、表示できません。C#でこの問題を処理する型の安全な方法はありますか? – Jules

+0

次に、そのメソッドを汎用的にします。 'public TList Foo (TList list)ここで、TList:MyList ' – dtb

+0

ありがとう。私はそれが問題を解決する方法を見ていない。たとえば、 'aMyList.Select((a)=> a.ToDisplayable())'を実行した場合、 'MyList 'を持っていましたが、GetControl()を呼び出すことができません。 MyDisplayableListではありません。 – Jules

1

ここではジェネリックも必要ですか?

IDisplayableを実装する複数のクラスがあり、そのすべてのインスタンスを同じリストに入れたいと思います。だから、あなたが本当に、同様にそのリスト内の非IDisplayableのインスタンスを入れて、共通の基本クラスを見つけて、

public class MyList2 : Collection<object>, IDisplayable 
{ 
    public void GetControl() 
    { 
     foreach (IDisplayable displayable in this.OfType<IDisplayable>()) 
     { 
      displayable.GetControl(); 
     } 
    } 
} 
1

を定義したい場合は、私が理由だと思い

public class MyList : Collection<IDisplayable>, IDisplayable 
{ 
    public void GetControl() 
    { 
     foreach (IDisplayable displayable in this) 
     { 
      displayable.GetControl(); 
     } 
    } 
} 

をちょうど必要があると思いますMyList<T>IDisplayableと非IDisplayableの両方で使用できるようにするには、重複した機能がいくつかあるからです。

MyListBase<T>という基本実装は、両方のリストで実行される基本機能を実装することをお勧めします。次に、MyDisplayableListにMyList(MyDisplayableList<T> : MyList<T> where T : IDisplayable)を継承させると、IDisplayableに固有の機能のみが実行されます。

IDisplayble以外の機能がある場合は、これらの機能を実行するためにNonDisplayableList<T> : MyListBase<T>を追加してください。

1

この問題のより良い解決策は、リストから抽象化し、compositeIDisplayableと考えることです。これは、たとえば、ASP.NETやWindows Formsなどでコントロールをモデル化する方法です。

その後
public class CompositeDisplayable : IDisplayable { 

    public void Add(IDisplayable displayable) { 
    // TODO: check for null, cycles, etc... 
    _list.Add(displayable); 
    } 

    public void Remove(IDisplayable displayable) { 
    // TODO: check for null 
    _list.Remove(displayable); 
    } 

    public Control GetControl() { 
    var control = new Control(); 
    // this assumes Control is also a composite type 
    _list.ForEach(displayable => control.Add(displayable.GetControl())); 
    return control; 
    } 

    private List<IDisplayable> _list = new List<IDisplayable>(); 

} 

、複合材料に「何か」のコレクションの間の橋渡しを、あなたはこのような拡張メソッドを作成することができます。

public static class DisplayableExtensions { 

    public static IDisplayable ToDisplayable(this IEnumerable source) { 
    if (source == null) throw new NullReferenceException(); // extension method should behave like instance methods 
    var result = new CompositeDisplayable(); 
    source. 
     OfType<IDisplayable>(). 
     ToList(). 
     ForEach(displayable => result.Add(displayable)); 
    return result; 
    } 

} 
関連する問題