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”)常规继承不够,因为无法设置继承类的属性。我认为当您坚持使用