序列化泛型类型列表

时间:2013-10-15 09:49:36

标签: c# generics xml-serialization

我正在编写一个包含任何数据类型的通用List序列化的应用程序。所以我设计了一个base-DataType来填充列表,如下所示:

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

此外,还有一个类GenericList实现IXmlSerializable - 接口来编写键值对,如下所示:

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

将产生以下XML:

<key>3</key>

GenericList的类定义或多或少如下:

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

所以我们假设我们有一个Person类,它来自GenericObject<string>(无论它看起来如何),我们希望用几个人来填充列表。我遇到的问题是在GenericList - 类的泛型类型T上定义约束,以便只有从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子句留空,但后来我必须检查TGenericList的类型,以便获取其键和值,我也失败了以下内容:

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

总是返回false,因为T属于Person类型,而不是GenericObject<object>

任何人都有一些建议如何填写我的名单?

1 个答案:

答案 0 :(得分:4)

您可以使用covariance。由于变体类型参数只能在接口和委托中声明(不在类定义中),因此还需要定义接口:

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))