将值与 C# 中的子类关联
Posted
技术标签:
【中文标题】将值与 C# 中的子类关联【英文标题】:Associate a value with a subclass in c# 【发布时间】:2011-03-20 04:43:24 【问题描述】:我有以下课程,我的问题在于它的 GetComponent 函数
class GameObject
private List<GameComponent> _components = new List<GameComponent>();
public void AddComponent(GameComponent component)
void RemoveComponent(string name)
public T GetComponent<T>(string name) where T : GameComponent
class GameComponent
public string Name get; set;
所以在 GetComponent 中我想获取由name
标识的组件并将其作为 T 返回。
所以我会打电话NavigationComponent navigation = gameObject.GetComponent<NavigationComponent>("navigation");
其中 NavigationComponent 将是 GameComponent 的子类
由于每个 NavigationComponent 实例只会具有相同的名称“导航”,我正在考虑是否可以做一些事情来将 GetComponent 简化为以下内容
NavigationComponent navigation = gameObject.GetComponent<NavigationComponent>();
提前致谢。
更新 1
我应该提一下,GameObject 的工作方式类似于一组 GameObject,由它们的名称标识,因此其中每个只能有一个。
所以要详细说明我们有class SimpleNavigation : GameComponent ...
class AdvancedNavigation : GameComponent ...
class SensorSystem : GameComponent ...
然后我会给 SimpleNavigation 和 AdvancedNavigation 命名为“navigation”,给 SensorSystem 命名为“sensor”
所以我不能在上面的例子中同时拥有 SimpleNavigation 和 AdvancedNavigation。
希望这是有道理的。
提前致谢。
附言我担心当没有太多收获和长期规范可能会改变时,我可能会设置太多约束,但这超出了我猜的问题范围
【问题讨论】:
你听说过依赖注入(IoC:控制反转)吗? 所以您想从GameComponent
的列表中获取NavigationComponent
?
不,我没有,我现在去查一下
@GenericTypeTea 是的,这是正确的
你使用的是什么版本的框架?
【参考方案1】:
更新:回应您的修改:
然后我会给 SimpleNavigation 和 高级导航名称 “导航”和到 SensorSystem 名称“传感器”
如果是这样的话,那你真的不能指望有这样的界面了……
public T GetComponent<T>() where T : GameComponent
...因为多个GameComponent
对象类型可能共享相同的名称。所以你不能从类型推断名称。
为什么不改用enum
呢?那么你可能会有这样的事情:
public enum ComponentType
Navigation,
Sensor // etc.
而您的GameObject
类又可以持有Dictionary<ComponentType, GameComponent>
。
那么您的GetComponent
方法可能如下所示:
GameComponent GetComponent(ComponentType type)
无论如何,这是一个想法......
我认为更有意义的是:
首先,如果您按名称查找,请使用Dictionary<string, GameComponent>
而不是List<GameComponent>
。这将为您提供 O(1) 的查找时间,而不是 O(N)。
现在,如果您希望名称依赖于类型,请像这样定义您的 GameComponent
类:
class GameComponent
public virtual string Name
// You could also hard-code this or cache it
// for better performance.
get return this.GetType().Name;
然后您可以选择覆盖派生方法中的 Name
属性,如下所示:
class NavigationComponent : GameComponent
public override string Name
// This returns the same thing as GetType().Name,
// but it's faster.
get return "NavigationComponent";
那么您的AddComponent
方法将是:
public void AddComponent(GameComponent component)
_components.Add(component.Name, component);
你的GetComponent
方法很简单:
public T GetComponent<T>() where T : GameComponent
return _components[typeof(T).Name] as T;
【讨论】:
我还没有输入你的代码,但是如果它不是静态的,我怎么能在类型上调用 .Name 呢? @Xtapodi:调用this.GetType().Name
将返回对象的type 名称(本身是System.Type
对象)。这通常没有意义,除非您已指定您实际上希望 GameComponent
对象的名称与其类型的名称相同。所以出于这个原因,Type.Name
属性正是您想要的。
感谢您的新更新。如果像虚拟静态方法这样的东西是可能的,那么我想我可以做到,我希望某些解决方案可能存在属性,它可能存在,但我想把它放在那里会是相当昂贵的性能明智的,我不会无论如何都能强制执行。但我从未使用过属性,所以我可能是错的。我可以强制 GameObject 子类具有 [ComponentType(string name)] 属性吗?【参考方案2】:
重写:
您已经提到 .Name
应该 作为属性保留在您的 GameComponent
类中——因此要考虑的一个选项是覆盖相等运算符以说“如果 @987654324 的两个实例@ 具有相同的名称,那么它们应该被视为相等”。结合使用OfType()
的Dave's suggestion,你会得到这样的结果:
class GameObject
private List<GameComponent> _components = new List<GameComponent>();
public T GetComponent<T>(string name) where T : GameComponent, new
return
(from c in _components.OfType<T>()
where c == new T Name = name
select c).FirstOrDefault();
class GameComponent
public string Name get; set;
public bool Equals(GameComponent other)
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return Equals(other.Name, Name);
public override bool Equals(object obj)
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
if (obj.GetType() != typeof(GameComponent))
return false;
return Equals((GameComponent)obj);
public override int GetHashCode()
return (Name != null ? Name.GetHashCode() : 0);
值得考虑是否要实施这种方法——它会影响任何相等检查(而不是引用检查)。然而,它是一种非常强大的能力,可以说“当 X 时,X 和 Y 应该被认为是相等的”——而等式重载让您可以在单个集中式主页(就在实体上)实现该逻辑。
【讨论】:
我已经实现了上面的方法,带有 FirstOrDefault 的 GetComponent 和一个 lamda,但我认为我不需要展示它,因为我真的想改变它。在第一个注释中,因为我想要拥有可能具有 NavigationComponent 和 SensesComponent 等的 GameObjects。在第二个注释中,为了避免从我调用它的地方投射它,我想调用它的代码行数更少。 啊,我不明白你的问题的意图。我已经用另一种方法更新了我的答案 - 在 this 情况下可能不是您需要的,但值得考虑【参考方案3】:首先,如果所有 NavigationComponents 都具有相同的名称,您将如何区分它们?如果您只想返回单个 NavigationComponent,则需要一个唯一标识符。
您可以使用 OfType() 方法返回一个类型的所有实例:
var navigationComponents = _components.OfType<NavigationComponent>();
从那里,您可以通过一些唯一标识符选择单个 NavigationComponent:
NavigationComponent nc = navigationComponents.Where(n => n.Id == 1);
【讨论】:
啊非常好,这似乎是我要找的。到目前为止,我认为每种类型只需要一个组件,但并非所有游戏对象都具有相同的组件集,一个可能有导航和传感器,一个可能只有一个传感器等。 你的回答让我对我想要实现的目标有了更好的思考,我已经更新了这个问题。以上是关于将值与 C# 中的子类关联的主要内容,如果未能解决你的问题,请参考以下文章
M Power Query - 通过将值与两个参考列进行比较,有条件地转换动态列数中的值