修改字典值作为out参数和参考

时间:2018-12-10 09:10:50

标签: c# 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
{
}

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

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

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

  

如果有人使用float创建新的MovementspeedComponent怎么办   运动速度

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

  

当我尝试修改组件时,不会通过引用对其进行修改

由于所有组件都是struct的这一行代码,因此:

components.TryGetComponent(out Position fooPosition)

获取我们在词典中拥有的结构的副本。 来自C# guide的引用:

  

结构在分配时被复制。将结构分配给新结构时   变量,将复制所有数据,并对新副本进行任何修改   不会更改原始副本的数据。这对   记住在使用诸如以下类型的值类型的集合时   字典。

     

如果有人使用float创建新的MovementspeedComponent怎么办   运动速度并尝试添加它?

答案 1 :(得分: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
}

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