简体   繁体   English

将C#泛型用于特定类型支持而无需硬编码类型比较

[英]Using C# generics for specific type support without hardcoding type comparision

I have function which takes in a serialized string, breaks the string apart to build however many objects it defines, and then returns a generic list. 我有一个函数,它接收一个序列化的字符串,将该字符串分解以构建它定义的许多对象,然后返回一个通用列表。 Here is the function and it is working exactly as I need it to: 这是函数,它正按我的需要正常工作:

// '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();
}

For lack of better words, I'm trying to do some "reverse polymorphism" without explicitly comparing each supported type 'T'. 由于缺少更好的词,我试图做一些“反向多态”而不明确地比较每个支持的类型“ T”。 For example, I would like to do this instead of the if , else if , ... : 例如,我想这样做,而不是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)));

Of course this does not work because a new BaseObject cannot be cast "forward" to an inherited class. 当然,这是行不通的,因为不能将新的BaseObject转换为继承的类。

I have tried having the function return an array of BaseObject s: 我试过让函数返回BaseObject的数组:

internal static BaseObject[] DeserializeData(string serializedData)

But this doesn't work when I am merging the return value into a List<BaseObjectSpecific1> (etc.) 但这在我将返回值合并到List<BaseObjectSpecific1> (等)。

I feel like am I missing something or making this more complicated than required. 我感觉好像我丢失了一些东西,或者使它变得比所需的更加复杂。 Is there a way I can support any type of BaseObject using generics without having to explicitly compare T to each inherited class type? 有没有一种方法可以使用泛型支持任何类型的BaseObject而不必将T与每个继承的类类型进行显式比较?

You can simply use Generics Constraints along with the new() constraint: 您可以简单地将泛型约束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();
}

This way, the compiler already knows that each T is deriving from BaseObject (hence having the BuildFromSerializedValue() method). 这样,编译器已经知道每个T都是从BaseObject (因此具有BuildFromSerializedValue()方法)。 And, by using the new() constraint it also knows that it's possible to create new instances of T because it's having a parameter-less constructor. 而且,通过使用new()约束,它还知道可以创建T新实例,因为它具有一个无参数的构造函数。

Also, you no longer need to explicitly cast item to T since the compiler already knows it is a T . 另外,您不再需要将item显式转换为T因为编译器已经知道它是 T

More on MSDN 有关MSDN的更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM