将字典值修改为 out 参数和引用

modifiy dictionary value as out parameter and reference

我想创建一个实体-组件-系统示例。我有像

这样的组件
internal struct Position : IComponent
{
    public int X { get; set; }
    public int Y { get; set; }
}

internal struct Movementspeed : IComponent
{
    public float Value { get; set; }
}

哪个实现

internal interface IComponent
{
}

循环遍历组件时,我想尽快找到它们。我想过创建一个字典,将组件类型作为键,将组件作为值。

internal class ComponentCollection
{
    public ComponentCollection()
    {
        components = new Dictionary<Type, object>();
    }

    private Dictionary<Type, object> components;

    public void AddComponent<T>(T component) // add a new component
    {
        Type componentType = typeof(T);
        components.Add(componentType, component as IComponent);
    }

    public void RemoveComponent(Type componentType) // remove the component by type
    {
        components.Remove(componentType);
    }

    public bool TryGetComponent<T>(out T component) // get the specified component
    {
        try
        {
            Type componentType = typeof(T);
            component = (T)components[componentType];
            return true;
        }
        catch (Exception)
        {
            component = default(T);
            return false;
        }
    }
}

出现了两个问题。

  1. 如果有人使用 float movementspeed 创建了一个新的 MovementspeedComponent 并试图添加它怎么办?有两个浮点数会引发重复键异常。我只能添加实现 IComponent 接口的自定义结构组件以防止重复。

  2. 当我尝试修改组件时,它们没有被引用修改

    private static void Main(string[] args)
    {
        ComponentCollection components = new ComponentCollection();
        components.AddComponent(new Position());
        components.AddComponent(new Movementspeed());
    
        if (components.TryGetComponent(out Position fooPosition))
        {
            fooPosition.X++;
            Console.WriteLine(fooPosition.X); // prints 1
        }
    
        if (components.TryGetComponent(out Position barPosition))
        {
            Console.WriteLine(barPosition.X); // prints 0
        }
    
        Console.ReadLine();
    }
    

有什么建议吗?

What if someone creates a new MovementspeedComponent using float movementspeed

当我们每种类型有一个 object/collection 时,类型对键有好处,否则 Dictionary<Type, object> 不合适,键应该是唯一的。

When I try to modify the components they are not modified by reference

由于所有组件都是 struct 这行代码:

components.TryGetComponent(out Position fooPosition)

获取字典中结构的副本。 引自 C# guide:

Structs are copied on assignment. When a struct is assigned to a new variable, all the data is copied, and any modification to the new copy does not change the data for the original copy. This is important to remember when working with collections of value types such as Dictionary.

What if someone creates a new MovementspeedComponent using float movementspeed and tries to add it?

我看到 2 个解决方案。使用 类 而不是结构,或者添加一些 Update 方法来更新字典中的结构

public void UpdateComponent<T>(T component)
{
    Type componentType = typeof(T);
    components[componentType] = component;
}

然后在完成更新结构后调用此方法:

if (components.TryGetComponent(out Position fooPosition))
{
    fooPosition.X++;
    components.UpdateComponent(fooPosition);
    Console.WriteLine(fooPosition.X); // prints 1
}

如果您将使用 类 而不是结构,您的旧解决方案应该可以工作。