我正在编写一个包含任何数据类型的通用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子句留空,但后来我必须检查T
中GenericList
的类型,以便获取其键和值,我也失败了以下内容:
if (typeof(T).IsAssignableFrom(typeof(GenericObject<object>)))
总是返回false,因为T
属于Person类型,而不是GenericObject<object>
。
任何人都有一些建议如何填写我的名单?
答案 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))