实现 "Virtual Static" 的好方法?用简单的例子

Good way to implement what "Virtual Static" could have? With simple example case

首先,让我明确一点,这不是另一个关于为什么 virtual static 不起作用的问题,所以请克制自己不要回答编译器如何看待 virtual 和 static 或将其标记为这些问题的重复,但如果您知道任何问题的答案符合我的示例,请随时 link 并标记重复。

现在,通过四处搜索如何实现本来可以通过这种方式解决的问题,很多人都说 "I don't even know why you would need to do that" 而少数几个试图提出与我相同问题的人的例子却截然不同示例,所以我发现很难将其他人的答案联系起来。

所以,在这个游戏中,我想制作一个简单的 InventoryItem 系统。每个 Item 都继承自一个 virtual classInventory class 可以识别

public class Item {
    public virtual static Sprite getIcon();
    public virtual static string getName();
}

public class Stone : Item {
    static Sprite icon;
    static string name = "Stone";

    public override static Sprite getIcon(){
        return icon;
    }
    public override static string getName(){
        return icon;
    }

    // ...
}

所以这个想法基本上是每个 Stone 在你的 Inventory 中共享相同的 icon 并且所有的石头都有相同的 name/title,比如在调试中使用消息或向玩家提供他正在查看或拾取的内容的一些消息。

现在我的胆量告诉我最好的做法是 Sprite 应该是 static,因为 InventoryStone 的所有实例都应该显示相同的icon。但是,各种项目也应该有一个 Sprite,因此它们应该 inherit 一个通用的 get 方法来检索这些。

所以我想出的两个备选方案感觉通常是错误的或过分错误的。

1) 使 get 方法成为非 static 并使它们 return 成为静态成员的内容。这是非常规的,因为它会为 class 的每个实例带来开销,其中每个实例的 return 值都相同。

编辑:更正,没有额外的开销,因此这种方法是可行的。

2) 制作一些母版 class,根据给定对象的类型存储所有 sprites/names 和 return。首先我不喜欢使用 type comparing/checking 因为我觉得如果可以的话最好避免这样做。但即便如此,我觉得这个解决方案对于 return a stringSprite reference

这样的琐碎任务来说还是有点矫枉过正

所以除非我遗漏了什么,否则没有直接的方法来实现这个目标吗?还是我的两种方法中的一种比我想象的要好?

PS:我要为一个 Unity 游戏实现这个,所以如果 unity 提供了一个解决方案,我会洗耳恭听。

通过评论者的一些澄清,我发现我所说的第一个解决方案实际上是我正在寻找的直接答案。简单地使变量静态,但 inherited/overriden 方法非静态,但使用它来检索静态值。

public class Item {
    public virtual Sprite getIcon();
    public virtual string getName();
}

public class Stone : Item {
    static Sprite icon;
    static string name = "Stone";

    public override Sprite getIcon(){
        return icon;
    }
    public override string getName(){
        return icon;
    }

    // ...
}

When in Rome, do as the Romans do. :)

如果您使用 C#,那么我建议避免使用 Java 风格的编码。

例如,方法名称采用 PascalCase 形式而不是 camelCase 形式,C# 也有 properties 而不是 getter/setter 方法。所以这是我的建议:

public abstract class Item
{
    public abstract Sprite Icon { get; }

    public abstract string Name { get; }
}

public class Stone : Item
{
    private static readonly Sprite icon = Sprite.Create(/* parameters omitted */);

    private const string name = "Stone";

    // expression-bodied member: supported as of C# 6
    public override Sprite Icon => icon;

    // traditional propery getter
    public override string Name
    {
        get
        {
            return name;
        }
    }
}

您在这里看到的内容:

  • 您可以覆盖用 abstractvirtualoverride 关键字标记的属性和方法。我将 Item class 及其属性设为 abstract,因此我不需要在 Item class 中实现属性,只需要派生类型 abstract =20=] 可以实例化,必须覆盖属性。
  • 由于 icon 字段的值不会改变,我也应用了 readonly 关键字,因此它无法更改。
  • name 字段也可以是 readonly,但我们使用 const 关键字代替 static readonly string 字段,这使得 name 字段不仅 [=28] =] 但它的值也不能改变。 请注意: static readonlyconst 的行为不同,请参阅 here
  • 覆盖的属性有两种形式:Name 属性 以传统的 C# 方式实现,Icon 属性 以新的 expression-bodied member 特征。

总结一下,没有冒犯,我的目的只是展示如何以更像 C# 的方式实现您的解决方案,这看起来不像 Java。