如何从C#中的类对象数组访问属性?

时间:2013-12-25 14:14:42

标签: c# arrays object properties polymorphism

    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”。

这个问题的解决方案是什么?

6 个答案:

答案 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转回他们的具体类型以便他们进行战斗,那么你将失去从多态性中获得的任何好处。如果你需要施放到CharacterBladewarrior进行战斗,这意味着你必须为每个角色编写不同的逻辑才能相互对抗。然后,如果您以后添加新的角色类型,则必须更新所有战斗代码以支持该类型。

你真正希望能够做的是编写一个生成战斗算法,可用于对抗任何两个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();