Character[] PlayerOne = new Character[5];
PlayerOne[1] = new BladeWarrior();
PlayerOne[2] = new FistWarrior();
PlayerOne[3] = new Archer();
PlayerOne[4] = new RedMage();
PlayerOne[5] = new BlueMage();
我知道通过多态,BladeWarrior可以是一个角色,但它不能反过来。我的问题是当我尝试访问数组的元素时。例如Player [1],我无法从BladeWarrior类访问函数和变量。它只允许我从BladeWarrior类继承的Character类中访问变量和函数。
如果我想要2个角色进行战斗,我将需要能够访问Bladewarrior函数/变量。
我想我可以使用“as”函数将PlayerOne [1]设置为特定对象。不完全是这样的:
string s = objArray[i] as string;
上面的代码行只是想知道我正在谈论哪个“as”。
这个问题的解决方案是什么?
答案 0 :(得分:2)
如果我想要2个角色进行战斗,我将需要能够访问Bladewarrior函数/变量。
看起来你正在尝试进行多次调度:你需要调用
Fight(PlayerOne[i], PlayerOne[j]);
调用一个知道两个字符的确切类型的函数。您可以使用不同的技巧来实现单一调度语言的双重调度,最值得注意的是visitor pattern。从C#4开始,您还可以使用dynamic
以相对简洁易读的方式实现双重调度:
static class FightArena {
public static void Fight(dynamic a, dynamic b) {
try {
DoFight(a, b);
} catch {
Console.Error.WriteLine("{0} and {1} cannot fight", a, b);
}
}
private static void DoFight(BladeWarrior a, Archer b) {
}
private static void DoFight(BladeWarrior a, FistWarrior b) {
}
private static void DoFight(BladeWarrior a, RedMage b) {
}
private static void DoFight(BladeWarrior a, BlueMage b) {
}
private static void DoFight(BladeWarrior a, BladeWarrior b) {
}
private static void DoFight(Archer a, Archer b) {
}
... // Enumerate all pairs that can fight
}
现在你可以这样写:
FightArena.Fight(PlayerOne[i], PlayerOne[j]);
并且调用将根据动态类型PlayerOne[i]
和PlayerOne[j]
到达确切的类型对。
答案 1 :(得分:1)
如果你必须将你的Character
转回他们的具体类型以便他们进行战斗,那么你将失去从多态性中获得的任何好处。如果你需要施放到Character
到Bladewarrior
进行战斗,这意味着你必须为每个角色编写不同的逻辑才能相互对抗。然后,如果您以后添加新的角色类型,则必须更新所有战斗代码以支持该类型。
你真正希望能够做的是编写一个生成战斗算法,可用于对抗任何两个Character
对象而不强制它们。您可以向Character
基类添加属性,以指示角色具有的属性。
例如,您可以向Attacks
类添加Character
属性,该属性将是角色具有攻击名称及其造成的伤害的攻击列表。然后每个派生的字符类将填充其Attacks
列表,您的战斗算法将处理这些攻击。通过这种方式,每个角色都可以拥有自己的攻击列表,但不必强制转换为特定的角色类型来访问它。
这里的最终目标是让任何外部代码只知道Character
类而不知道它的任何派生类。这将使您的外部代码更清晰,并使您能够在将来添加或删除字符类。
答案 2 :(得分:0)
这是绝对正常的,如果您想要访问BladeWarrior的属性,您必须将Character
转换为BladeWarrior
,而您可以使用as
关键字:
BladeWarrior bw = PlayerOne[1] as BladeWarrior;
答案 3 :(得分:0)
您向上转发这些实例,这就是您只能使用parent
类行为和属性的原因。
我认为你必须为所有实例单独做。
BladeWarrior player1 = new BladeWarrior();
FistWarrior player2 = new FistWarrior();
Archer player3 = new Archer();
//and so on
答案 4 :(得分:0)
如你所说,你可以使用"作为"施放。如果您尝试强制转换的实例无法转换为目标类,则将获得null。
var currentCharacter = PlayerOne[1] as BladeWarrior;
if(currentCharacter != null)
{
....
}
这里的挑战是如何清楚地了解什么是正确的铸造。 也许你可以使用数组中的结构并使用一个标志来指示下层类
switch(PlayerOne[1].Type)
{
case PlayerTypes.BladeWarrior:
currentCharacter = PlayerOne[1].Character as BladeWarrior;
}
但总的来说,似乎你没有完成Liskov Subtitution Principle(SOLID原则中的L)。您不需要访问特定类型字符的实现细节,只需覆盖某些方法或使用基于策略模式的更模块化(和复杂)设计。
答案 5 :(得分:0)
或者您可以使用界面
public interface ICharacter {
int myValue { get; set;}
void myMethod();
}
public class BladeWarrior : ICharacter {
private int myPrivateValue;
public int myValue { get { return myPrivateValue; } set { myPrivateValue = value; } }
public void myMethod() {
//Do what you want
}
}
ICharacter[] PlayerOne = new ICharacter[5];
PlayerOne[0] = new BladeWarrior();
然后您可以访问您的界面方法 ICharacter [0] .myMethod();