我有一个函数,它接收一个序列化的字符串,将该字符串分解以构建它定义的许多对象,然后返回一个通用列表。这是函数,它正按我的需要正常工作:
// 'T' only supports specific types - those derived from BaseObject.
internal static T[] DeserializeData<T>(string serializedData)
{
var data = new List<T>();
// Break into individual serialized items and decode each.
foreach (var serializedItem in (serializedData ?? "").Split(','))
{
// Skip empty entries.
if (serializedItem == "")
{
continue;
}
// Base class which 'T' will always be derived from.
BaseObject item = null;
// Initialize object based on the generic type provided.
if (typeof(T) == typeof(BaseObjectSpecific1))
{
item = new BaseObjectSpecific1();
}
else if (typeof(T) == typeof(BaseObjectSpecific2))
{
item = new BaseObjectSpecific2();
}
// Add additional checks for BaseObjectSpecific3, etc.
item.BuildFromSerializedValue(serializedItem);
data.Add((T)Convert.ChangeType(item, typeof(T)));
}
return data.ToArray();
}
由于缺少更好的词,我试图做一些“反向多态性”而不显式地比较每种支持的类型“ T”。例如,我想这样做,而不是
if
,else if
,...
:// Create a new object and then convert it to the generic type T.
// Then cast it back to the base object so we can access the deserialize method.
var item = (BaseObject)Convert.ChangeType(new BaseObject(), typeof(T));
item.BuildFromSerializedValue(serializedItem);
data.Add((T)Convert.ChangeType(item, typeof(T)));
当然,这是行不通的,因为不能将新的
BaseObject
强制转换为继承的类。我试过让函数返回
BaseObject
的数组:internal static BaseObject[] DeserializeData(string serializedData)
但这在将返回值合并到
List<BaseObjectSpecific1>
中时不起作用(等)我感觉好像我丢失了一些东西,或者使它变得比所需的复杂。有没有一种方法可以使用泛型支持任何类型的
BaseObject
,而无需显式比较T与每个继承的类类型? 最佳答案
您可以简单地将Generics Constraints与new()
约束一起使用:
internal static T[] DeserializeData<T>(string serializedData)
where T : BaseObject, new()
{
var data = new List<T>();
// Break into individual serialized items and decode each.
foreach (var serializedItem in (serializedData ?? "").Split(','))
{
// Skip empty entries.
if (serializedItem == "")
continue;
T item = new T();
// Add additional checks for BaseObjectSpecific3, etc.
item.BuildFromSerializedValue(serializedItem);
data.Add(item);
}
return data.ToArray();
}
这样,编译器已经知道每个
T
都是从BaseObject
派生的(因此具有BuildFromSerializedValue()
方法)。而且,通过使用new()
约束,它还知道可以创建T
的新实例,因为它具有一个无参数的构造函数。同样,您不再需要将
item
强制转换为T
,因为编译器已经知道它是T
。有关MSDN的更多信息