2

この投稿の問題と同様の問題があります。

また、特定の基本クラスを拡張するジェネリック クラスを、基本クラスの型のコレクションに入れることができるという何千もの投稿もオンラインで見てきました。私はこれを完全によく理解しています。

私の問題は、上記のリンクされた投稿や他の投稿とは、1 つの基本的な点で異なります。私のジェネリック クラスには、ジェネリックでもある基本クラスがあります。さらに悪いことに、これは非常に大規模な MVVM アプリケーション フレームワーク (社内で構築) の一部であり、一般的な基本クラスにも基本クラスなどがあります。各基本クラスは特定のプロパティと機能を追加し、このように見えます。 :

DataListEntry<T> <-- BaseSynchronisableDataType<T> <-- BaseAuditDataType <-- BaseDataType <-- BaseAnimatableDataType

アプリケーション コレクション クラスは、同様の継承を使用します。

DataList<T> <-- BaseSynchronisableCollection<T> <-- BaseAnimatableCollection<T> <-- BaseCollection<T> <-- SortableObservableCollection<T>

さらに悪いことに、各ジェネリック宣言には制約があるため、たとえば BaseSynchronisableDataType<T> の定義は次のようになります。

public abstract class BaseSynchronisableDataType<T> : BaseAuditDataType, 
    ISynchronisable<T>, ICloneable<T>, IEquatable<T> where T : class, ICloneable<T>,
    IEquatable<T>, new()

したがって、各ジェネリック コレクション型は、これらの制約を通じてジェネリック基本クラスに結び付けられます。うまくいけば、私の問題の規模がわかります。

インターフェイス (上には表示されていません) を使用して、コレクションからそれぞれの基本クラスへのリンクを削除しようとしましたが、関連するクラスの一般的な制約のためにこれも失敗しています。たとえば、一部の基本クラスには必要な一般的な「クラス」制約があり、コレクションの型は「非抽象型でなければならない」というエラーが表示されるため、インターフェイスの型のコレクションを作成できませんでした。ジェネリック型またはメソッドでパラメーター 'T' として使用するためのパブリック パラメーターなしコンストラクター。

注意すべき最後のポイントは、私がやろうとしていることを正確に説明しています。

DataList<T> 基本クラスをすべて拡張するさまざまなクラスをコレクションに設定する必要があります。これらのクラスは名前が異なるだけで、プロパティはまったく同じです。それらは次のように宣言されています。

public class Writer : DataListEntry<Writer>    
public class Artist : DataListEntry<Artist>etc.

何かアイデアがあれば教えてください... 私はすでにこの問題で 2 日間苦しんでいますが、上司はあまり満足していません! よろしくお願いします、シェリダン。

4

3 に答える 3

7

ここで理解する必要がある重要な原則があります。 が のサブクラスであってもFoo<Child>、クラスは のサブクラスではないということです。つまり、には String または Int32 を含めることができる以上のインスタンスを含めることはできません。Foo<Parent> ChildParentList<Foo<Parent>>List<Foo<Child>>

この理由を理解するために、次のコードを想像してください (コンパイルされませんが、上記のステートメントが真である必要がある理由を示しています)。

var myIntList = new List<Int>();
var myObjectList = (List<Object>)myIntList;

// Uh oh, now I can add a string to a list of integers...
myObjectList.Add("Foo");

不思議なことに繰り返されるテンプレート パターンを使用すると、すべてのクラス間の継承階層がなくなります。基本クラスを共有しなくなったため、より具体的なリストに入れることはできません。List<Object>

あなたの場合の最善のアプローチは、おそらく DataListEntry が実装する非ジェネリック インターフェイスを作成し、そのインターフェイスのリストを作成することです。インターフェイスがその型のインスタンスで必要なすべてのメンバーを提供する場合、準備は完了です。

例えば:

public interface IDataListEntry { 
    bool QuacksLikeADuck { get; } 
    bool WalksLikeADuck { get; }
}

public abstract class DataListEntry<T> : IDataListEntry where ... {
    // Implement these in subclasses
    abstract bool QuacksLikeADuck { get; } 
    abstract bool WalksLikeADuck { get; } 
}

次に、次のことができます。

List<IDataListEntry> myDataListEntries = new List<IDataListEntry>();
myDataListEntries.Add(new Writer(...));
myDataListEntries.Add(new Artist(...));
IEnumerable ducks = myDataListEntries.Where(dle => dle.WalksLikeADuck && dle.QuacksLikeADuck);

Tまたは(おそらくあなたの状況により適切です)、の特定のインスタンスのType を知る必要がある場合IDataListEntry

public interface IDataListEntry { 
    Type TheTypeOfT { get; }
}

public class DataListEntry<T> : IDataListEntry where ... {
    Type TheTypeOfT { get { return typeof(T); } }
}

そして、次のようにします。

List<IDataListEntry> myDataListEntries = new List<IDataListEntry>();
myDataListEntries.Add(new Writer(...));
myDataListEntries.Add(new Artist(...));
IEnumerable artists = myDataListEntries.Where(dle => typeof(Artist).IsAssignableFrom(dle.TheTypeOfT));
于 2012-08-08T16:52:05.110 に答える
0

わかりましたので、問題は次のことを宣言できなかったことです

DataList<Artist> artists = new DataList<Artist>();

拡張するジェネリッククラスのジェネリック制約のために、BaseDataListEntryクラスがジェネリックではなかった場合。ジェネリックではないため、クラスが拡張できない型である必要がありました。ビューモデルのコレクションにすべての異なるコレクションを入れることができるように、クラスをジェネリックにしない必要がありました(ユーザーの選択に応じて一度に1つずつ)。BaseSynchronisableCollection<T>DataList<T>TBaseSynchronisableDataType<T>BaseDataListEntryBaseDataListEntryDataList<T>DataList<BaseDataListEntry>

解決策は、インターフェイスを作成しIBaseSynchronisableDataType<T>、具象BaseSynchronisableDataType<T>クラスの代わりにジェネリック制約で使用することでした。次に、それをクラスに実装したBaseDataListEntryので、すべての制約が満たされました。なぜ以前に見なかったのかわからない。

いつもありがとうございます。

于 2012-08-08T20:56:03.117 に答える
0

基本に戻って、いくつかの単純な linq を使用して、クラスのフィルター処理されたリストを取得します。

タイプオブジェクトのリストを宣言DataList<object> Lし、タイプを求められたらL.OfType<Type>()、リストをフィルタリングする呼び出しを行います。object は、結局のところ、使用できる最も一般的なものになります。すべてが拡張された基本型を使用できるかもしれませんが、その抽象型であるため、その型でリストを宣言できるかどうかはわかりません。

私自身のコードでは、一般的な制約を使用して同様のことを実現しています。

public abstract class BusinessObjectBase : //some interfaces
{
    //class stuff and events
}

基本クラスを拡張する宣言されたオブジェクトがたくさんあり、これを実行できるようになりました

Collection<BusinessObjectBase> temp = new Collection<BusinessObjectBase>();
temp.Add(new RXEvents());
temp.Add(new RXBattery());
temp.Add(new RXBHA());

ここで、私がリストに追加している各クラスはすべて、BusinessObjectBase を拡張することによって作成されています。非常に似たようなことを試みていますが、基本的な実装は異なります。基本型自体をテンプレートとして宣言すると、基本型が壊れます。Base は Base と同じであり、この 2 つはオブジェクト以外の共通点を実装していません。

Base<>Base<X>またはとは関係ありませんBase<Y>。今、あなたがこのようにそれをデカールした場合

public abstract class BaseSynchronisableDataType<T> : BaseAuditDataType, ISynchronisable<T>, ICloneable<T>, IEquatable<T> where T : MyCustomBaseClass, ICloneable<T>, IEquatable<T>, new()

表すMyCustomBaseClassすべてのオブジェクトがその子であることが保証されているため、リスト型として使用できます。<T>ただし、これは BaseSynchronisableDataType を作成する目的を無効にしているように見えます...

于 2012-08-08T16:55:26.097 に答える