如何在C#中实现“静态重载常量”?

7
我正在使用C#创建一个游戏。每个关卡由多个瓷砖组成,每个瓷砖都属于不同的类型,如草地、木墙等。
理想情况下,我想创建一个基类“Tile”,并从中继承来创建每种类型的瓷砖类。我希望每个瓷砖类的属性都是某种静态/常量/等成员,因为每种类型的瓷砖只会有相同的属性。也就是说,我不希望100个瓷砖都有一个属性,这些属性都具有相同的值,这似乎效率低下。
但在C#中无法实现这样的需求。有没有什么方法可以实现我想要的效果?
我的备选方案是将其分成两棵树:一个只包含“Tile”类,表示实例;另一个是“TileType”,我会为每种类型实例化一个对象,并通过某种“TileTypeCollection”访问它们。但这种方法感觉很奇怪,我更愿意采用第一种方式。
处理这种情况时是否有任何一般性的指导方针?

1
在面向对象编程中,扩展基本类型的目的是修改或添加行为,而不是突变属性。您的示例仅需要一个Tile类 - 可以有不同类型的瓷砖,但这些只是Tile的属性。假设您的瓷砖类型具有虚拟方法PlayerEntered(),您可以有一个名为BlockingTile的派生Tile类,它将覆盖PlayerEnetered()并阻止玩家,或者您可以有一个名为BurningTile的类,它将覆盖*PlayerEntered()*并使玩家着火。 - MattDavey
问题在于瓷砖具有某些属性,例如它们的纹理名称。对于某种类型,该值将始终具有相同的值。因此,实例化100个相同类型的瓷砖会感觉非常糟糕,因为会创建100个包含永远不会改变的相同字符串的属性。 - Zeta Two
稍微离题一点,如果你有100个瓷砖,它们的属性都设置为常量字符串“grass”,编译器将使所有引用指向单个实例,而不是创建100个字符串实例。这意味着每个瓷砖只消耗4(或8)个字节的引用,所以情况并没有你想象的那么糟糕。 - Dan Bryant
1
这正是享元模式的设计目的所在,就像Marino Simic所建议的那样 :) 每个瓦片是否真的需要一个字符串属性来存储纹理名称?这才是使得每个瓦片独特的原因吗?不是的...... 我认为在这种情况下,一个Tile只需要两个属性:游戏世界中的位置和瓦片类型标识符......瓦片类型的属性(如纹理)就在这里。 - MattDavey
5个回答

4

这感觉像是最好的解决方案。非常感谢。 - Zeta Two
另外,您是否有使用XNA框架的经验?如果有,您会说内容导入器是否使用了这种模式? - Zeta Two

2
您可以按照以下方式创建一个类结构:
public abstract class Tile
{
  public abstract string BaseType;
}

public class Floor : Tile
{
  public override string BaseType
  {
    get
    {
       return "floor";
    }
  }
}

public class Grass : Tile
{
  public override string BaseType
  {
    get
    {
       return "grass";
    }
  }
}

public class Wooden : Tile
{
  public override string BaseType
  {
    get
    {
       return "wooden";
    }
  }
}

1
这是多态的完全误用。扩展类型的目的是添加/修改行为,而不是提供不同的数据 - MattDavey
@MattDavey:谢谢你指出这个问题。实际上我想请教一下这个解决方案的意见,因为我的背景是C++,最近当我想在C#中实现同样的功能时,我是这样做的。你能告诉我你喜欢这里的哪个解决方案吗?这样我就知道如何在C#中思考了。 - Ozair Kafray
1
在面向对象编程中,一个对象由两个部分组成 - 属性(属性)和行为(方法)。您可以随时更改对象的属性,但要添加或更改行为需要多态性(不考虑其他模式,例如装饰器)。如果您看到我在原始问题中的评论,我给出了多态性可能是必要的示例 :) - MattDavey

1

你不能只使用静态字段来支持你的瓦片基类上的属性吗?

public abstract class Tile
{
  private static string _commonProperty

  public static string CommonProperty
  {
    get { return _commonProperty; }
    set { _commonProperty = value; }
  }
}

4
那么这个属性也应该是静态的。 - Guffa
不一定 - 拥有一个返回共享值的属性可能是有用的。(当你实现一个接口时,拥有一个具有默认但可重写值的属性,从一个类继承或准备该类用于继承...) - Jean Hominal
@Jean Hominal:但是这个属性将返回该类的所有子类共享的值,从我的理解来看,问题希望为每个子类返回不同的值。 - Ozair Kafray

0
一种方法是在子类上有静态属性,在基类中有一个非静态虚拟访问器,当被重写时返回静态值。

0

根据具体要求,有几个选项可以考虑。

如果存在一个公共属性,其值因每种类型而异,则在基类中声明它,将其设置为只读值,并在每种类型的构造函数中设置它。

如果您有仅存在于特定类型上的属性,则应在子类中声明这些属性,并同样设置为只读。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接