0

私は、任意のデータ型を保持するジェネリック List のシリアル化のためのアプリケーションを作成しています。

public abstract class GenericObject<T> {
    public string key;
    public T value;

    public GenericObject() { }
    public GenericObject(string key, T value) : this() { 
        this.key = key;
        this.value = value;
    }
}

さらに、次のようにキーと値のペアを書き込むために -Interface をGenericList実装するクラスがあります。IXmlSerializable

GenericObject<int> myInt = new GenericObject<int>("key", 3);

次の XML が生成されます。

<key>3</key>

のクラス定義は、GenericList多かれ少なかれ次のとおりです。

public class GenericList<T> : IXmlSerializable {
    List<T> objects;
    // ...
}

では、 (どのように見えても)Personから派生するクラスがあり、リストを 2 人の人物で埋めたいとします。GenericObject<string>私が抱えている問題は、クラスのジェネリック型 T に制約を定義して、GenericListから派生した型のみが可能になるようにすることですGenericObject。を使用して既に試しましたpublic class GenericList<T> : IXmlSerializable where T : GenericObject<object>が、次のコンパイラ エラーのために機能しませんでした。

Person' cannot be used as type parameter 'T' in the generic type or method 'GenericList<T>'. There is no implicit reference conversion from 'Person' to 'GenericObject<object>'

where句を空のままにしてみましたが、キーと値を取得するために の型をチェックする必要がTありGenericList、次のようにも失敗しました。

if (typeof(T).IsAssignableFrom(typeof(GenericObject<object>))) 

Tタイプ Person であり not であるため、常に false を返しますGenericObject<object>

私のリストを人で埋める方法を誰か提案してもらえますか?

4

1 に答える 1

4

共分散を使用できます。バリアント型パラメーターは (クラス定義ではなく) インターフェイスとデリゲートでのみ宣言できるため、インターフェイスも定義する必要があります。

public interface IGenericObject<out T>
{
    string Key { get; }
    T Value { get; }
}

public abstract class GenericObject<T> : IGenericObject<T>
{
    public string Key { get; set; }
    public T Value { get; set; }

    protected GenericObject() { }

    protected GenericObject(string key, T value)
        : this()
    {
        this.Key = key;
        this.Value = value;
    }
}

public class GenericList<TGenericObject> : IXmlSerializable
    where TGenericObject : IGenericObject<object>
{
    private readonly List<TGenericObject> _list = new List<TGenericObject>();

    public void Add(TGenericObject item)
    {
        _list.Add(item);
    }

    public XmlSchema GetSchema()
    {
        // ...
    }

    public void ReadXml(XmlReader reader)
    {
        // ...
    }

    public void WriteXml(XmlWriter writer)
    {
        // ...
    }
}

public class Person : GenericObject<string>
{

}

今、あなたはこれを行うことができます:

public class SomeClass
{
    public void SomeMethod()
    {
        Person somePerson = new Person();

        GenericList<IGenericObject<object>> listWithGenericsOfObject = new GenericList<IGenericObject<object>>();
        listWithGenericsOfObject.Add(somePerson);

        GenericList<IGenericObject<string>> listWithGenericsOfString = new GenericList<IGenericObject<string>>();
        listWithGenericsOfString.Add(somePerson);

        GenericList<Person> listWithGenericsOfPerson = new GenericList<Person>();
        listWithGenericsOfPerson.Add(somePerson);
    }
}

IsAssignableFrom を使用して、実行時に型をチェックする必要がなくなりました。ただし、必要に応じて、次のようにタイプを交換する必要があります。

typeof(GenericObject<object>).IsAssignableFrom(typeof(T))
于 2013-10-15T10:25:05.117 に答える