在 C# 中,如何让一个对象的属性仅由该对象的组件修改?

How would I have properties of an object modified only by components of that object in C#?

假设我的游戏中有一个界面,IItem。 IItem 表示具有渲染组件、权重和附加 "process" 的对象。该过程可能由某人使用某种能力影响该项目来附加。也许类似于 RPG 中的 "enchantment"。假设我希望附加进程能够修改 IItem 的权重。但是,我只希望作为 IItem 组件的进程能够这样做。 IItem 之外的对象需要能够获得权重。

我是否在界面中仅使用 getter 来实现权重 属性?那么基础 class 是否实现了一个 "SetWeight" 方法,该方法在 Item 命名空间内部声明?当然,这仍然不能真正保证只有特定 IItem 拥有的组件才能影响它,但至少 Input 命名空间中的某些东西不能直接改变项目的权重。在 C 中,我可以做一些类似于内核中的链接列表的事情,它可以获得它们的容器,这将给我一种方法来确保权重和进程具有相同的容器对象,但是,我没有看到一个简单的方法来做到这一点在 C# 中。此外,我认为组件必须引用回其父组件会损害基于组件的设计。

这是我在设计界面和 classes 时 运行 遇到的一个普遍问题。

嗯,我想我明白你在说什么了。

确保您的过程,例如IEnchantment 可能将 IItem 作为依赖项(将其保留为成员),并使 IItem 具有采用 IEnchantment 的 Update/Set 方法,然后您可以检查,例如:

public void Update(IEnchantment enchantment)
{
    if (enchantment.AttachedItem != this)
        throw new Exception("Cannot Update Item!");
    /*
     * Execute Updating Logics
     */
}

Here's one library我尝试为自己的游戏设计,也许它可以帮助你思考一些事情。它远非完美,几乎什么都不是,但我希望它能以任何方式提供帮助。

您是否考虑过使用字典而不是属性?像这样:

// Item base class
public Dictionary<string, object> Attributes { get; private set; }

public List<Process> Enchantments { get; private set; }

public virtual T Get<T>(string identifier)
{
    var att = this.Attributes.FirstOrDefault(att => att.Key == identifier);
    if (att == null) throw new MissingAttributeExeption(identifier); // Or perhaps just return default(T)
    if ((att.Value is T) == false) throw new InvalidAttributeCastException(identifier, typeof(T));  

    var value = att.Value;
    foreach (var ench in this.Enchantments)
    {
        ench.Modify(identifier, ref value);
    }

    return value as T; // Maybe you need to cast value to Object, and then to T, I can't remember.
}

// Process class

public string ValueToModify { get; set }

public virtual void Modify(string identifier, ref object value)
{
    if (identifier != this.ValueToModify) return;

    // In an inherited class, for example a Weightless-Enchantment: Halfs all weight
    var castedVal = value as int
    value = castedVal / 2;
    // Now this one item weights 50% of normal weight, and the original value is still stored in Item's Attributes dictionary.
}

// Some random class

public void Update()
{
    var totalWeight = 0;
    foreach (var item in this.itemCollection)
    {
        int weight = item.Get<int>("Weight");
        totalWeight += weight;
    }
    Console.WriteLine("The player weights: {0}", totalWeight);
}

显然这意味着您不能真正对属性进行硬编码,但是...您真的想这样做吗,在漫长的 运行 中?我的意思是一旦你开始增加智力、敏捷、力量、耐力、耐力等

我知道这不能解决您提出的问题,但我认为这是一个相当不错的选择。