为什么基本 class 方法不遵守 new 关键字?
Why isn't the new keyword respected by base class methods?
我正在制作一个复杂的纸牌游戏。所以我有一个 class Card
,它有一些特定于这个游戏的属性,例如 List<Effect> effects
。 class 还有一些基本方法可以将其效果解析为可读的英语,GetParsedEffects()
可以遍历列表并将它们解析为字符串。
public class Card {
public List<Effect> effects;
public string GetParsedEffects() {
foreach(Effect e in effects)
//formatting stuff
}
}
现在我决定要创建一个非常特殊的效果,即创建一张卡片的同卵双胞胎。当我说同卵双胞胎时,我的意思是一张卡总是与另一张卡具有相同的值,并且当其中任何一个更新值时,两者都会受到影响。这就像有 2 张完全相同的卡片(但它们不能 完全 相同,因为当你玩其中一张时,我需要知道它是哪一张,这样就不会 两个都进入了弃牌堆。)
我试图通过继承来做到这一点。所以我创建了一个childclassTwinCard : Card
。 TwinCard 有一个额外的 属性、Card original
,并在所有属性上使用 new
关键字,以便它们获取和设置原始卡的属性而不是它自己的属性。所以基本上,你有一张原始卡,然后 twin-card 只反映原始卡,对双卡的改动会影响原始卡。由于两者共享 Card
为 class,因此所有方法都可以相同地使用它们。
public class TwinCard : Card {
public Card original;
public new List<Effect> effects { get { return original.effects;} set { original.effects = value; } }
public TwinCard(Card original) {
this.original = original;
}
}
我对自己很满意。
直到我尝试在所有手牌上跟注 GetParsedEffects()
,包括 TwinCard。由于这是一个基本 class 方法,它似乎使用基本 class 字段 effects
而不是标有 new
关键字的 TwinCard 版本。所以它试图使用据称隐藏的 effects
基数 class,而不是 new List<Effect> effects
.
我的印象是 new
关键字意味着任何和所有调用都将交换为 new
版本,但事实并非如此。我是做错了什么,还是我误解了 new
的工作原理?
我认为这与我遍历手牌的方式有关,将牌定义为 Card
;
foreach(Card c in hand) {
c.GetParsedEffect();
}
例证:
我有一张名为 Concentrate 的卡片,其列表中有 1 个效果。
我有一张 TwinCard,其原始设置为 Concentrate。
在调试模式下 (Visual Studio),我可以看到 2 个名为“effects”的字段,一个为空,另一个具有 Concentrate 中引用的效果。
当我在 TwinCard 上输入 GetParsedEffects() 时,它在列表中显示效果为 0,据说它使用了一个效果字段,而不是另一个。
如果这是 C# 错误,我该如何解决?
如果这是预期的行为,我将如何设计它?我看到的唯一其他选择是针对每个属性的更改实施事件和侦听器,并让 TwinCard 根据这些侦听器更新自己的值。但那是一个巨大的听众网络。
您误解了 new
关键字。 new
从使用 class 的代码中隐藏了原始成员,而不是从基础 class 中隐藏了原始成员。您想要的是 virtual
,在 class 中覆盖的 virtual
成员替换了基本成员。看这个例子:
public class Card
{
public virtual string eff { get; set; } = "basecard";
public void PrintEffect()
{
Console.WriteLine(eff);
}
}
public class NewCard : Card
{
public new string eff { get; set; } = "newcard";
}
public class VirtualCard : Card
{
public override string eff { get; set; } = "virtualcard";
}
public static void Main()
{
Card c = new Card();
c.PrintEffect();
Console.WriteLine(c.eff);
NewCard cs = new NewCard();
cs.PrintEffect();
Console.WriteLine(cs.eff);
VirtualCard cv = new VirtualCard();
cv.PrintEffect();
Console.WriteLine(cv.eff);
}
你会得到一个结果
basecard
basecard
basecard
newcard
virtualcard
virtualcard
如您所见,new
属性 只能被使用显式类型 NewCard
的代码看到,但是 virtual
被新代码看到和基本代码。
此外,要演示它,请检查:
Card c = new NewCard();
c.PrintEffect();
Console.WriteLine(c.eff);
你认为它会打印什么?
万一您认为“basecard newcard”...好吧,您错了,它会显示“basecard basecard”,因为我们使用的是类型 Card
而不是 NewCard
所以此代码不 'sees' new
属性.
我正在制作一个复杂的纸牌游戏。所以我有一个 class Card
,它有一些特定于这个游戏的属性,例如 List<Effect> effects
。 class 还有一些基本方法可以将其效果解析为可读的英语,GetParsedEffects()
可以遍历列表并将它们解析为字符串。
public class Card {
public List<Effect> effects;
public string GetParsedEffects() {
foreach(Effect e in effects)
//formatting stuff
}
}
现在我决定要创建一个非常特殊的效果,即创建一张卡片的同卵双胞胎。当我说同卵双胞胎时,我的意思是一张卡总是与另一张卡具有相同的值,并且当其中任何一个更新值时,两者都会受到影响。这就像有 2 张完全相同的卡片(但它们不能 完全 相同,因为当你玩其中一张时,我需要知道它是哪一张,这样就不会 两个都进入了弃牌堆。)
我试图通过继承来做到这一点。所以我创建了一个childclassTwinCard : Card
。 TwinCard 有一个额外的 属性、Card original
,并在所有属性上使用 new
关键字,以便它们获取和设置原始卡的属性而不是它自己的属性。所以基本上,你有一张原始卡,然后 twin-card 只反映原始卡,对双卡的改动会影响原始卡。由于两者共享 Card
为 class,因此所有方法都可以相同地使用它们。
public class TwinCard : Card {
public Card original;
public new List<Effect> effects { get { return original.effects;} set { original.effects = value; } }
public TwinCard(Card original) {
this.original = original;
}
}
我对自己很满意。
直到我尝试在所有手牌上跟注 GetParsedEffects()
,包括 TwinCard。由于这是一个基本 class 方法,它似乎使用基本 class 字段 effects
而不是标有 new
关键字的 TwinCard 版本。所以它试图使用据称隐藏的 effects
基数 class,而不是 new List<Effect> effects
.
我的印象是 new
关键字意味着任何和所有调用都将交换为 new
版本,但事实并非如此。我是做错了什么,还是我误解了 new
的工作原理?
我认为这与我遍历手牌的方式有关,将牌定义为 Card
;
foreach(Card c in hand) {
c.GetParsedEffect();
}
例证: 我有一张名为 Concentrate 的卡片,其列表中有 1 个效果。 我有一张 TwinCard,其原始设置为 Concentrate。 在调试模式下 (Visual Studio),我可以看到 2 个名为“effects”的字段,一个为空,另一个具有 Concentrate 中引用的效果。 当我在 TwinCard 上输入 GetParsedEffects() 时,它在列表中显示效果为 0,据说它使用了一个效果字段,而不是另一个。
如果这是 C# 错误,我该如何解决? 如果这是预期的行为,我将如何设计它?我看到的唯一其他选择是针对每个属性的更改实施事件和侦听器,并让 TwinCard 根据这些侦听器更新自己的值。但那是一个巨大的听众网络。
您误解了 new
关键字。 new
从使用 class 的代码中隐藏了原始成员,而不是从基础 class 中隐藏了原始成员。您想要的是 virtual
,在 class 中覆盖的 virtual
成员替换了基本成员。看这个例子:
public class Card
{
public virtual string eff { get; set; } = "basecard";
public void PrintEffect()
{
Console.WriteLine(eff);
}
}
public class NewCard : Card
{
public new string eff { get; set; } = "newcard";
}
public class VirtualCard : Card
{
public override string eff { get; set; } = "virtualcard";
}
public static void Main()
{
Card c = new Card();
c.PrintEffect();
Console.WriteLine(c.eff);
NewCard cs = new NewCard();
cs.PrintEffect();
Console.WriteLine(cs.eff);
VirtualCard cv = new VirtualCard();
cv.PrintEffect();
Console.WriteLine(cv.eff);
}
你会得到一个结果
basecard
basecard
basecard
newcard
virtualcard
virtualcard
如您所见,new
属性 只能被使用显式类型 NewCard
的代码看到,但是 virtual
被新代码看到和基本代码。
此外,要演示它,请检查:
Card c = new NewCard();
c.PrintEffect();
Console.WriteLine(c.eff);
你认为它会打印什么?
万一您认为“basecard newcard”...好吧,您错了,它会显示“basecard basecard”,因为我们使用的是类型 Card
而不是 NewCard
所以此代码不 'sees' new
属性.