将值与 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&lt;NavigationComponent&gt;("navigation"); 其中 NavigationComponent 将是 GameComponent 的子类

由于每个 NavigationComponent 实例只会具有相同的名称“导航”,我正在考虑是否可以做一些事情来将 GetComponent 简化为以下内容

NavigationComponent navigation = gameObject.GetComponent&lt;NavigationComponent&gt;();

提前致谢。

更新 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&lt;ComponentType, GameComponent&gt;

那么您的GetComponent 方法可能如下所示:

GameComponent GetComponent(ComponentType type)  

无论如何,这是一个想法......


我认为更有意义的是:

首先,如果您按名称查找,请使用Dictionary&lt;string, GameComponent&gt; 而不是List&lt;GameComponent&gt;。这将为您提供 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&lt;NavigationComponent&gt;();

从那里,您可以通过一些唯一标识符选择单个 NavigationComponent:

NavigationComponent nc = navigationComponents.Where(n =&gt; n.Id == 1);

【讨论】:

啊非常好,这似乎是我要找的。到目前为止,我认为每种类型只需要一个组件,但并非所有游戏对象都具有相同的组件集,一个可能有导航和传感器,一个可能只有一个传感器等。 你的回答让我对我想要实现的目标有了更好的思考,我已经更新了这个问题。

以上是关于将值与 C# 中的子类关联的主要内容,如果未能解决你的问题,请参考以下文章

在 MySql 中,有没有办法将值与列中的数字进行比较?

M Power Query - 通过将值与两个参考列进行比较,有条件地转换动态列数中的值

我应该如何在不使用 C++ 中的构造函数的情况下将值(不是指针)转换为子类?

如何将子表值与父表行关联并插入子表值对应于php中的父表行

构造函数中的 C# 默认值与序列化的两个构造函数相同

如何将嵌套的子表值与父表行关联并插入子表值对应于php中的父表行