首页 文章

modifiy dictionary value作为out参数和引用

提问于
浏览
1

我想创建一个Entity-Component-System示例 . 我有像这样的组件

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
{
}

循环遍历组件时,我希望尽可能快地找到它们 . 我想过创建一个Dictionary,它将组件类型作为键,组件作为值 .

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;
        }
    }
}

有两个问题出现了 .

  • 如果有人使用 float movementspeed 创建新的MovementspeedComponent并尝试添加它会怎么样?有两个浮点数会抛出一个重复的键异常 . 我只能添加实现 IComponent 接口的自定义struct组件以防止重复 .

  • 当我尝试修改组件时,它们不会被引用修改

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();
}

有什么建议?

2 回答

  • 1

    我看到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
    }
    

    如果您将使用类而不是结构,那么您的旧解决方案应该可行 .

  • 2

    如果有人使用float movespeed创建新的MovementspeedComponent,该怎么办?

    当我们每种类型都有一个对象/集合时类型适用于键,否则 Dictionary<Type, object> 不合适,键应该是唯一的 .

    当我尝试修改组件时,它们不会被引用修改

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

    components.TryGetComponent(out Position fooPosition)
    

    获取字典中包含的struct的副本 . 来自C# guide的报价:

    结构将复制结构 . 将结构分配给新变量时,将复制所有数据,并且对新副本的任何修改都不会更改原始副本的数据 . 在处理诸如Dictionary之类的值类型集合时,这一点很重要 . 如果有人使用float movespeed创建一个新的MovementspeedComponent并尝试添加它会怎么样?

相关问题