用派生类重写属性

本文关键字:属性 重写 派生 | 更新日期: 2023-09-27 18:19:17

我试着把一个大的类分成3个独立的类:

具有共享功能的基类

仅具有服务器功能的服务器类

一个只有客户端功能的客户端类

我遇到的问题是我不能用派生类重载属性。

下面我准备了一个基类及其服务器对应类的代码示例。

我离某处很远,但我希望能够调用"基类"函数,并与覆盖的派生类一起工作。

public class Battlefield
{
    public Tile[,] Tiles { get; set; }
    public virtual Game Game { get; set; }
    public Battlefield(int sizeX, int sizeY, Game game)
    {
        Tiles = new Tile[sizeX, sizeY];
        Game = game;
    }
    public Tile GetTile(int x, int y)
    {
        return Tiles[x, y];
    }
}
public class ServerBattleField : Battlefield
{
    public override ServerGame Game  { get; set; }
    public ServerBattleField(int sizeX, int sizeY, ServerGame game) : base(sizeX, sizeY, game)
    {
    }
    public void DoSomethingServerSpecific()
    {
        Game.DoSomethingServerSpecialWithTile(10,5);
    }
}
public class Game
{
    public virtual Battlefield Battlefield {get;set;}
    public Game(int sizeX, int sizeY)
    {
        Battlefield = new Battlefield(sizeX,sizeY,this);
    }
    public void DoSomethingWithTile(int x, int y)
    {
        Battlefield.GetTile(x,y).DoSomethingWithTile();
    }

}
public class ServerGame : Game
{
    public override ServerBattleField Battlefield {get;set;}
    public ServerGame(int sizeX, int sizeY)
        : base(sizeX, sizeY)
    {
    }
    public void DoSomethingServerSpecialWithTile(int x, int y)
    {
        Battlefield.GetTile(x, y).DoSomethingWithTile();
        Battlefield.GetTile(x, y).DoSomethingSpecialWithTile();
    }
}
public class Tile {
    public void DoSomethingWithTile() { }
    public void DoSomethingSpecialWithTile() { }
}

用派生类重写属性

您的重写属性必须尊重精确的基类属性的签名。

在您的特定情况下,您需要

public class ServerBattleField : Battlefield
{
    public override ServerGame Game  { get; set; } //CHANGE TO RETURN TYPE GAME
    ....
}

:

public class ServerBattleField : Battlefield
{
    public override Game Game  { get; set; } //CHANGE TO RETURN TYPE GAME
    ....
}

注意它与属性名本身重叠:不好,最好更改它以避免将来命名

时混淆。

问题就像Tigran在属性签名中解释的那样。如果你想为每个派生类自定义类型,你可以使用泛型。

public class ServerBattleField : Battlefield<GameType>
{
}

其中Battlefield为:

public class Battlefield<T>
{
    public T Game { get; set; }
}

你可以强制T从一个基本的Game类或接口派生。

不需要再派生这个属性了。

使用泛型是一个很好的方法,你的战地类将是这样的:

public class Battlefield<T> where T: Game
{
    public Tile[,] Tiles { get; set; }
    public T Game { get; set; }
    public Battlefield(int sizeX, int sizeY, T game)
    {
        Tiles = new Tile[sizeX, sizeY];
        Game = game;
    }
    public Tile GetTile(int x, int y)
    {
        return Tiles[x, y];
    }
}
public class ServerBattleField : Battlefield<ServerGame> 
{
    public ServerBattleField(int sizeX, int sizeY, ServerGame game)
        : base(sizeX, sizeY, game)
    {
    }
    public void DoSomethingServerSpecific()
    {
        Game.DoSomethingServerSpecialWithTile(10, 5);
    }
}

您不能重载仅根据返回类型不同的内容。原因:

ServerGame oServer = new ServerGame();
BattleField oBF = oServer.BattleField; //No way to know which BattleField property to return.

您可以覆盖具有相同签名的东西,并且由于ServerBattleField继承自BattleField,因此从BattleField属性返回ServerBattleField类型的对象没有问题。如果需要ServerBattleField功能,使用它的代码只需要知道将其强制转换为正确的类型。

此外,请注意,任何访问ServerGameBattleField属性的代码,即使它被定义为返回BattleField对象,它使用任何派生类的重写功能。