如何确保 C# 中的列表始终具有特定元素?

How to ensure that a List in C# always has a specific element?

我有一个名为 class 的 GameObject,它有一个动态的组件列表。这些组件可以随时删除和添加。组件可能是纹理、声音或过渡等。确保此列表始终具有一个过渡组件的最佳方法是什么?每种类型只允许一个组件。

我有两个可能的解决方案。其中哪一个是最好的? 这个问题有更好的解决方案吗?

方法一:

class GameObject {
    private List<Component> components;

    public T GetComponent<T>() where T : Component {
        // search the requested component and return it
        foreach(Component comp in components) {
            if(comp is T) return (T)comp;
        }
        // return null or throw exception when not found
        return null;
    }

    public void RemoveComponent<T>() where T : Component {
        if(typeof(T) != typeof(Transition)) {
            // only remove the componenent if it's not a Transition component
            Component tmp;
            foreach(Component comp in components) {
                if(comp is T) tmp = comp;
                break;
            }
            components.Remove(tmp);
        }
    }
}

方法二:

class GameObject {
    // separate variable for the transition component
    private Transition transition;
    private List<Component> components;

    public T GetComponent<T>() where T : Component {
        // if a transition is requestet just return it
        if(typeof(T) == typeof(Transition)) {
            return transition;
        }
        // else: search the requested component in the list
        foreach(Component comp in components) {
            if(comp is T) return (T)comp;
        }
        // return null or throw exception when not found
        return null;
    }

    public void RemoveComponent<T>() where T : Component {
        if(typeof(T) != typeof(Transition)) {
            // only remove the componenent if it's not a Transition component
            Component tmp;
            foreach(Component comp in components) {
                if(comp is T) tmp = comp;
                break;
            }
            components.Remove(tmp);
        }
    }
}

您似乎在尝试创建所谓的实体组件模型。我建议分析一些使用该模型的引擎,例如 Paradox Game Engine.

Entity (GameObject) and PropertyContainer(组件集合)您应该特别感兴趣。

将转换组件保留为单独的字段并将其存储在组件列表中可能是个好主意。由于它保证是每个游戏对象的一部分,因此您可以提供单独的 getter 属性 以直接访问此组件以绕过任何查找成本。

由于您似乎每种类型只允许一个组件,因此将组件存储在 Dictionary<Type, Component> 中会更有效。与迭代组件和进行类型比较相比,这将提供真正快速的查找。

第二种方法的略微修改版本:

class GameObject
{        
    private readonly Transition transition = new Transition();
    private readonly Dictionary<Type, Component> components = new Dictionary<Type, Component>();        

    public GameObject()
    {
        AddComponent(transition);
    }

    public Transition Transition { get { return transition; } }

    public T GetComponent<T>() where T : Component
    {
        Component component;
        if (components.TryGetValue(typeof (T), out component))
        {
            return (T) component;
        }
        return null;
    }

    public void AddComponent<T>(T component) where T : Component
    {
        Type type = typeof (T);
        if (!components.ContainsKey(type))
        {
            components.Add(type, component);
        }
    }

    public void RemoveComponent<T>() where T : Component
    {                        
        if (typeof(T) != typeof(Transition))
        {
            components.Remove(typeof (T));                
        }
    }
}