[英]How can I use an expression tree to call a generic method when the Type is only known at runtime?
[英]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.