使用C#泛型进行特定类型支持,无需硬编码类型比较

时间:2014-10-14 18:32:38

标签: c# generics polymorphism

我有一个函数,它接受一个序列化的字符串,将字符串分开以构建它定义的许多对象,然后返回一个通用列表。这是函数,它完全按照我的需要工作:

// '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'。例如,我想这样做而不是ifelse 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 s:

的数组
internal static BaseObject[] DeserializeData(string serializedData)

但是当我将返回值合并到List<BaseObjectSpecific1>(等等)

时,这不起作用

我觉得我错过了一些东西,或者说这比想要的更复杂。有没有办法可以支持任何类型的BaseObject使用泛型,而不必明确地将T与每个继承的类类型进行比较?

1 个答案:

答案 0 :(得分:5)

您可以简单地使用Generics Constraintsnew()约束:

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