繁体   English   中英

我如何声明具有不同和未知类型的泛型列表?如何使用仅在运行时已知的类型初始化泛型?

[英]How could I declare list of generics with different and unknown types and How could I initialize a generic with a type only known at runtime?

这是一个2部分的问题。

首先
我有一个名为ComponentList的类,如下所示:

public class ComponentList<T> : List<T> where T : Component
{

}

现在我想创建一个无类型ComponentLists的空列表:

List<ComponentList<>> MasterList = new List<ComponentList<>>();

我得到一个错误,因为ComponentList想要指定泛型类型,即使我还没有尝试初始化任何ComponentLists(只是包含它们的MasterList)。 如何在不初始化任何ComponentLists的情况下声明ComponentLists的MasterList(因为我计划在运行时使用仅在运行时知道的类型初始化它们)? 毕竟,MasterList需要包含不同泛型类型的ComponentLists,而不仅仅是一个。

其次
我知道之前已经问过这个,但我似乎无法理解任何提出的解决方案的概念。

如您所知,我有一个List<>名为MasterList,它是ComponentLists(自定义类)的列表。 ComponentList是未定义类型的泛型类(被约束为Component的子类型)。

在下面的示例中,我试图检查ComponentList泛型类型(从MasterList引用)是否与此类(从中调用代码的类)相同。

if (MasterList[i].GetType() == typeof(ComponentList<this.GetType()>))
{

}

问题是,代码意味着从未知的子类中自动调用,而不是从此父类调用。 因此,需要将ComponentList泛型类型与子类的类型进行比较,而不是与此基类进行比较。 因此,“this.GetType”取代了实际基类的硬编码名称。

在ComponentList <>中传递的this.GetType()类型显然返回“类型预期”错误,因为GetType()返回编译时类型,而不是运行时类型(这是我需要的)。

那我怎么能得到运行时类型? 如果我不能,那么完成我想要做的事情的最佳选择是什么? (我听过一些关于可能对我有帮助的事情,但我真的不明白)。

您无法在运行时确定泛型类型。 C#(所有.Net,实际上)都是故意设计的。 编译器以与显式定义的类型几乎相同的方式处理泛型类型。

考虑以下:

class MyGenericClass<T>
{
    public static T MyProperty { get; set; }
}

class MyIntClass
{
    public static int MyProperty { get; set; }
}

class UseThem
{
    public void test()
    {
        // both are JIT'ed to be exactly the same machine code
        var foo = MyGenericClass<int>.MyProperty;
        var bar = MyOtherClass.MyProperty;
    }
}

因此,您必须为泛型类提供一个类型,以便JIT知道要编译的内容。

可能的替代方案如果可能最终成为泛型类型的所有可能类型都相似(从相同的基类继承或实现类似的接口),那么您可以使用接口或基类作为泛型类型实例化泛型类:

List<ComponentList<ComponentBase>> MasterList = new List<ComponentList<ComponentBase>>();
// -OR-
List<ComponentList<IMyComponent>> MasterList = new List<ComponentList<IMyComponent>>();

我有一种预感,你应该能够通过一点点创意重构来定义一个公共接口或基类。 :)

当我试图为用C#编写的游戏设置实体组件系统时,我也遇到了这个问题。 实际上没有办法将组件存储为实际类型,您必须将它们全部存储为Component并进行转换。

我设置的方式是将Dictionary<Type, List<Component>>作为ComponentManager类的私有成员。 添加组件的方法是通用的,并检查它的Type是否包含在Dictionary中,因此获取IEnumerable<SpecificComponent>就像这样简单:

public IEnumerable<T> EnumerateComponents<T>()
    where T : Component
{
    foreach (Component c in components[typeof(T)])
        yield return (T)c;
}

(您还需要检查字典是否包含typeof(T) ,该位是内置的,我的自定义集合继承自Dictionary,以避免在这种情况下出现异常。)

只要在一般方法之外永远不修改字典(并且绝对不能从外部直接访问),类型安全就是“保证”的。 不理想,但它足够快,永远不会成为你的瓶颈。

编辑

需要探索的东西可能是C#4的dynamic关键字。 我没有深入研究过,但是将组件存储为List<dynamic>可能会更好(或者它可能会引入太多开销),只需要考虑一些事情。

我不认为你问的是可能的,但也许这就是你所需要的。

public class ComponentA : Component { }
public class ComponentB : Component { }
public class Component { }

public class ComponentList<T> : List<T> where T : Component
{

}

class Program
{
    static void Main(string[] args)
    {
        ComponentList<Component> MasterList = new ComponentList<Component>();

        MasterList.Add(new ComponentA());
        MasterList.Add(new ComponentB());

        for (int i = 0; i < MasterList.Count; i++)
        {
            if (MasterList[i] is ComponentA)
            {
            }

        }
    }
}

暂无
暂无

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

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