问题描述
我想创建能够通过匹配类型将列表转换为元组(或结构)的方法。 我还需要为多个元组组件计数创建重载,例如,我可以调用:
var t1 = GetAsTuple<(HealthComponent)>(components);
var t2 = GetAsTuple<(PositionComponent,ModelComponent)>(components);
var t3 = GetAsTuple<(Texture,ModelComponent,PositionComponent)>(components);
因为我有很多这些组合,所以我称它们为组件元组,我想避免大量样板代码,并希望有一个通用机制来填充这些元组。
这是我试过的,显然它不能编译:
public T GetAsTuple<T>(Component[] components)
where T : ValueTuple<x,y>,new()
where x : Component
where y : Component
{
var t = new T();
t.Item1 = components.OfType<x>().Single();
t.Item2 = components.OfType<y>().Single();
return t;
}
是否有可能我正在尝试做或有另一种方法来获得所需的行为。 我知道我可以通过反射达到我想要做的事情,但这对于上下文(游戏开发)来说太慢了。
解决方法
获取您指定的这些元组的解决方案实际上需要许多非常相似的方法。如果您查看 .Net 源代码,您会发现这实际上是 Tuple.Create 方法的工作方式:
var t1 = GetAsTuple<HealthComponent>(components);
var t2 = GetAsTuple<PositionComponent,ModelComponent>(components);
var t3 = GetAsTuple<Texture,ModelComponent,PositionComponent>(components);
public Tuple<T1> GetAsTuple<T1>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>());
public Tuple<T1,T2> GetAsTuple<T1,T2>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>(),components.GetComponent<T2>());
public Tuple<T1,T2,T3> GetAsTuple<T1,T3>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>(),components.GetComponent<T3>(),components.GetComponent<T2>());
... etc ...
// I would still use this extension
public static class ComponentExtensions
{
public static T GetComponent<T>(this Component[] components)
{
return components.OfType<T>().Single(); // note this will throw if 0 or more than 1 are in the array.
}
}
,
现在我将坚持使用基于反射的解决方案。
当我有时间时,我将实现一个 T4 模板,它为我生成方法重载。
,您可以有一个更简单的方法来获取特定组件:
public static class ComponentExtensions
{
public static T GetComponent<T>(this Component[] components)
{
return components.OfType<T>().Single(); // note this will throw if 0 or more than 1 are in the array.
}
}
然后我希望你有处理特定事物并需要某些组件的类:
public class SomethingDoer
{
private readonly PositionComponent _position;
private readonly ModelComponent _model;
public SomethingDoer(Component[] components)
{
_position = components.GetComponent<PositionComponent>();
_model = components.GetComponent<ModelComponent>();
}
public void DoSomething()
{
...
}