Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
190 views
in Technique[技术] by (71.8m points)

c# - serialize list of generic type

I am writing an application for serialization of a generic List that holds any datatype.So I designed a base-DataType to fill the list with as follows:

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

Furthermore there is a class GenericList which implements the IXmlSerializable-Interface to write a key-value pair as like this:

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

Which will produce the following XML:

<key>3</key>

The class-definition for the GenericList is more or less as follows:

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

So let′s assume we have a class Person that derives from GenericObject<string>(no matter how it looks like) and we want to fill the list with a couple of persons. The problem I have is defining a constraint on the generic type T of the GenericList-class so that only types are possible that derive from GenericObject. I already tried it by using public class GenericList<T> : IXmlSerializable where T : GenericObject<object> but that did not work because of the following compiler error:

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

I also tried out leaving the where-clause empty, but then I have to check the type of T within the GenericList in order to get its key and value where I also failed with the following:

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

which will always return false as T is of type Person and not GenericObject<object>.

May anyone have some suggestion how I can fill my list with a person?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use covariance. Since variant type parameters only can be declared in interfaces and delegates (not in class definitions), you also need to define an interface:

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

}

Now you can do this:

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

Now you don't need to check the type at runtime using IsAssignableFrom. However, in case you will need it, you should swap the types like this:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...