C# 如何扩展类';s的功能?

C# 如何扩展类';s的功能?,c#,C#,这是一个简单的概念,我以前没有遇到过麻烦,因此非常感谢您的帮助 public partial class Player { public string Name { get; private set; } public int Id { get; private set; } } public partial class ExtendedPlayer : Player { public string Color = ""; } public clas

这是一个简单的概念,我以前没有遇到过麻烦,因此非常感谢您的帮助

public partial class Player
{
    public string Name
    { get; private set; }

    public int Id
    { get; private set; }
}

public partial class ExtendedPlayer : Player
{
    public string Color = "";
}

public class MainProgram
{
    static void Main()
    {
        Player p = new Player();

        // The following creates a null object "ep":
        ExtendedPlayer ep = p as ExtendedPlayer;

        // For proof, NullReferenceException is thrown here:
        ep.Color = "red";
    }
}
我在上面读到的其他一些文章求助于创建
ep
,然后手动将
p
的所有值分配给它。这是不可能的,因为
Player
仅可读

我读过的另一个解决方案是将
Player
制作成
界面
,但我也不能这样做,因为有Player对象


另外,在我的情况下,
Player
实际上是库的一部分。我创建了库,因此可以更改其属性,但我不希望属性可编辑。但是,如果这造成了问题,我可以改变它是局部的事实。

你不能从一个玩家向上投射到另一个扩展玩家。看起来您正在使用c#-is,所以请看一下扩展方法


我不完全清楚为什么不在main中创建ExtendedPlayer而不是Player类型。ExtendedPlayer是从Player派生的,因此您不能将Player转换为ExtendedPlayer,但可以将ExtendedPlayer转换为Player。

您不能从Player向上转换为ExtendedPlayer。看起来您正在使用c#-is,所以请看一下扩展方法


我不完全清楚为什么不在main中创建ExtendedPlayer而不是Player类型。ExtendedPlayer派生自Player,因此您不能将播放机转换为ExtendedPlayer,但可以将ExtendedPlayer转换为播放机。

您可以创建
Player
的受保护构造函数,用于初始化值:

public class Player {
    // other stuff same as in your example...

    protected Player(string name, int id) {
        this.Name = name;
        this.Id = id;
    }
}

public class ExtendedPlayer : Player {
    public ExtendedPlayer(Player p) : base(p.Name, p.Id) { }
}

// in your Main method, you can create an ExtendedPlayer from a Player like so:

Player p = new Player();

ExtendedPlayer e = new ExtendedPlayer(p);
有一件事:
as
操作符不会将对象从一种类型转换为另一种类型。相反,它试图将一个变量的值强制转换为不同的类型。这些类型必须兼容。不能将任何类型强制转换为任何其他类型。您可以在此处和其他地方阅读有关铸造的信息:

另一件事:您需要某种方法来初始化
Player
类中的字段。现在,这些值将是默认值(字符串为null,int为0)。也许您有更多我们看不到的代码,所以这可能不是问题。但是,请注意,初始化播放机的机制与派生类初始化属于基类
player
的字段的方式有关(如上面的代码所示)


您需要问自己的问题是,为什么要将
播放器
转换为
扩展播放器
。为什么不首先创建
ExtendedPlayer
?我认为您的模型可能没有得到很好的考虑,所以请花一些时间思考一下,在将
播放器
转换为
扩展播放器
时,您实际要做的是什么,也许这个问题会消失。

您可以创建一个
播放器
的受保护构造函数来初始化值:

public class Player {
    // other stuff same as in your example...

    protected Player(string name, int id) {
        this.Name = name;
        this.Id = id;
    }
}

public class ExtendedPlayer : Player {
    public ExtendedPlayer(Player p) : base(p.Name, p.Id) { }
}

// in your Main method, you can create an ExtendedPlayer from a Player like so:

Player p = new Player();

ExtendedPlayer e = new ExtendedPlayer(p);
有一件事:
as
操作符不会将对象从一种类型转换为另一种类型。相反,它试图将一个变量的值强制转换为不同的类型。这些类型必须兼容。不能将任何类型强制转换为任何其他类型。您可以在此处和其他地方阅读有关铸造的信息:

另一件事:您需要某种方法来初始化
Player
类中的字段。现在,这些值将是默认值(字符串为null,int为0)。也许您有更多我们看不到的代码,所以这可能不是问题。但是,请注意,初始化播放机的机制与派生类初始化属于基类
player
的字段的方式有关(如上面的代码所示)


您需要问自己的问题是,为什么要将
播放器
转换为
扩展播放器
。为什么不首先创建
ExtendedPlayer
?我认为您的模型可能没有得到很好的考虑,所以请花一些时间思考一下,在将
播放器
转换为
扩展播放器
时,您实际上在做什么,也许这个问题会消失。

如果您想动态地向类添加功能/行为,您应该研究一下装饰器模式。ExtendedPlayer的实现如下所示:

public interface IPlayer
{
  string Name {get;}
  string Id {get;}
}

public class Player: IPlayer
{
    public string Id {get; private set;}
    public string Name {get; private set;}
    Player (string name, string id)
    {
        Name = name;
        Id = id;
    }
}

public class ExtendedPlayer: IPlayer
{
    private IPlayer  _player;
    public string Id {get { return _player.Id; }}
    public string Name {get { return _player.Name + ", " + Color; }}
    public string Color{ {get;set;}
    Player (IPlayer player, string color)
    {
        _player = player;
        Color = color;
    }
}

IPlayer player = new Player("12", "Video player");
player = new ExtendedPlayer(player, "red");
Console.WriteLine(player.Id);                      // prints 12
Console.WriteLine(player.Name);                    // prints Video player, red
Console.WriteLine(((ExtendedPlayer)player).Color); // prints red

如果您想动态地向类添加功能/行为,那么应该研究decorator模式。ExtendedPlayer的实现如下所示:

public interface IPlayer
{
  string Name {get;}
  string Id {get;}
}

public class Player: IPlayer
{
    public string Id {get; private set;}
    public string Name {get; private set;}
    Player (string name, string id)
    {
        Name = name;
        Id = id;
    }
}

public class ExtendedPlayer: IPlayer
{
    private IPlayer  _player;
    public string Id {get { return _player.Id; }}
    public string Name {get { return _player.Name + ", " + Color; }}
    public string Color{ {get;set;}
    Player (IPlayer player, string color)
    {
        _player = player;
        Color = color;
    }
}

IPlayer player = new Player("12", "Video player");
player = new ExtendedPlayer(player, "red");
Console.WriteLine(player.Id);                      // prints 12
Console.WriteLine(player.Name);                    // prints Video player, red
Console.WriteLine(((ExtendedPlayer)player).Color); // prints red

沮丧**。它让人困惑——但是这些术语来自类图,其中基类在上面,派生类在下面。所以,你的意思实际上是向下投射。。因为它是向下的。稍微澄清一下:)为什么要使用扩展方法?Tx Simon-我永远无法保持这些方法的正确性。沮丧**。它让人困惑——但是这些术语来自类图,其中基类在上面,派生类在下面。所以,你的意思实际上是向下投射。。因为它是向下的。稍微澄清一下:)为什么要使用扩展方法?Tx Simon-我永远都无法保持这些方法的正确性。我认为当所有装饰类都使用相同的公共成员时,装饰器模式更有用。否则,正如您的代码所演示的那样,您最终不得不强制转换,并且没有得到很多好处。在这种情况下,我不知道你为什么不做普通的继承。我不知道原始代码的意图是什么,为什么常规的内在性是不够的。我同意,decorator模式通常使用不变的接口,这就是我添加它的原因。但是假设播放器的属性设置器必须是私有的,并且ExtendedPlayer需要替换原始播放器,那么类似包装器的场景通常是最好的。也许第二行应该是:ExtendedPlayer ExtendedPlayer=newextendedplayer(player,“red”)常规继承不够,因为无法设置继承类的属性。我认为当您坚持使用