C#-1つのリスト内の複数のジェネリック型


153

これはおそらく不可能ですが、私はこのクラスを持っています:

public class Metadata<DataType> where DataType : struct
{
    private DataType mDataType;
}

それ以外にもありますが、簡単にしましょう。ジェネリック型(DataType)は、whereステートメントによって値型に制限されています。私がやりたいのは、さまざまなタイプ(DataType)のこれらのメタデータオブジェクトのリストを用意することです。といった:

List<Metadata> metadataObjects;
metadataObjects.Add(new Metadata<int>());
metadataObjects.Add(new Metadata<bool>());
metadataObjects.Add(new Metadata<double>());

これは可能ですか?


24
以下の回答のアプローチには、単にList<object>?それらはボックス化/ボックス化解除を停止せず、キャストの必要性を取り除きません。そして最終的にMetadata、実際のについて何も知らないオブジェクトを取得していDataTypeます。これらの問題に対処する解決策を探していました。インターフェース/クラスを宣言する場合、実装/派生したジェネリック型をジェネリックリストに入れることができるようにするために、無意味なレイヤー以外のを使用する場合とどのように違うのList<object>ですか?
Saeb Amini、

9
抽象基本クラスとインターフェースの両方が、リストに追加できる要素のタイプを制限することにより、ある程度の制御を提供します。ボクシングがこれにどのように組み込まれるかもわかりません。
0b101010 2014

3
もちろん、.NET v4.0以降を使用している場合は、共分散が解決策です。List<Metadata<object>>トリックを行います。
0b101010 2014

2
@ 0b101010私は同じことを考えていましたが、残念ながら値の型での分散は許可されていません。OPにはstruct制約があるため、ここでは機能しません。参照
nawfal 2014

@ 0b101010、どちらも参照型のみを制限し、組み込みの値型と構造体は引き続き追加できます。また、最終的に、MetaData元の値型の代わりに参照型のリストがあり、各要素の基になる値型に関する(コンパイル時の)情報がないため、実質的に「ボックス化」されます。
Saeb Amini、2014

回答:


195
public abstract class Metadata
{
}

// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
    private DataType mDataType;
}

5
うわー!それが可能だとは本当に思っていませんでした。あなたは命の恩人です、男!
Carl、

2
+10これ!なぜこれがコンパイルされるのかわかりません。
Odys 2011

同様の問題がありますが、ジェネリッククラスが別のジェネリッククラスから拡張されているため、ソリューションを使用できません...この状況の修正に関するアイデアはありますか?
シェリダン

10
単純な方法と比較して、このアプローチには利点がありList<object>ますか?OPの質問の下に投稿された私のコメントを見てください。
Saeb Amini、

11
@SaebAmini List <object>は、開発者に意図を示しません。また、リストに非MetaDataオブジェクトを誤って追加して、開発者が足元を狙うことを防ぎません。List <MetaData>を使用することにより、リストに何が含まれるべきかが理解されます。最も可能性の高いMetaDataには、上記の例では示されていないいくつかのパブリックプロパティ/メソッドがあります。オブジェクトを介してそれらにアクセスするには、面倒なキャストが必要になります。
バズ

92

レッピーの答えに従ってMetaData、インターフェースを作ってみませんか:

public interface IMetaData { }

public class Metadata<DataType> : IMetaData where DataType : struct
{
    private DataType mDataType;
}

なぜこのアプローチが優れているのか誰かに教えてもらえますか?
Lazlo、2010

34
共通の機能が共有されていないため、その上で基本クラスを無駄にするのはなぜですか?インターフェースは十分です
flq

2
構造体でインターフェースを実装できるからです。
DamianLeszczyński-2012年

2
ただし、仮想メソッドを使用したクラスの継承は、インターフェイスメソッドよりも約1.4倍高速です。したがって、MetaData <DataType>に非ジェネリックMetaData(仮想)メソッド/プロパティを実装する場合は、パフォーマンスが問題になる場合は、インターフェイスではなく抽象クラスを選択してください。それ以外の場合は、インターフェースを使用する方がより柔軟になります。
TamusJRoyce 2012

30

newキーワードを使用して、非ジェネリックバージョンも使用しました。

public interface IMetadata
{
    Type DataType { get; }

    object Data { get; }
}

public interface IMetadata<TData> : IMetadata
{
    new TData Data { get; }
}

明示的なインターフェイスの実装を使用して、両方のDataメンバーを許可します。

public class Metadata<TData> : IMetadata<TData>
{
    public Metadata(TData data)
    {
       Data = data;
    }

    public Type DataType
    {
        get { return typeof(TData); }
    }

    object IMetadata.Data
    {
        get { return Data; }
    }

    public TData Data { get; private set; }
}

値のタイプをターゲットにしたバージョンを導出できます。

public interface IValueTypeMetadata : IMetadata
{

}

public interface IValueTypeMetadata<TData> : IMetadata<TData>, IValueTypeMetadata where TData : struct
{

}

public class ValueTypeMetadata<TData> : Metadata<TData>, IValueTypeMetadata<TData> where TData : struct
{
    public ValueTypeMetadata(TData data) : base(data)
    {}
}

これは、あらゆる種類の一般的な制約に拡張できます。


4
+1の使用方法を示しているだけで(DataTypeそしてobject Data多くの助けになった)
Odys

4
たとえば、書けないようですDeserialize<metadata.DataType>(metadata.Data);シンボルメタデータを解決できないことを示しています。ジェネリックメソッドに使用するためにDataTypeを取得する方法
・クール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.