如何使用字符串在C#中调用对象?

aco*_*ime 1 c# variables

我目前正在制作一个基于控制台的简单RPG地牢游戏,对C#还是很陌生,我在学校上了视觉基础课程,并且团结一致玩了大约一个月。

我的问题是,我正在编程玩家将会遇到的第一场战斗。我已经构造了一些武器,并且希望能够用一个单独的字符串来调用此人当前的武器,例如,我当前的武器是匕首或对象wp1,我希望将我的“武器”附加到wp1以某种方式,我可以做类似的事情, Console.WriteLine("Damage: " + weapon.dmg);而不是对wp1.dmg进行硬编码,以便在游戏制作的后期,当玩家有机会购买更好的武器时,我可以使用变量来做,例如,播放器现在具有短剑(wp2)

private string weapon = "wp2"; ... Console.WriteLine("Damage: " + weapon.dmg);

我试图简单地说, String weapon = wp1;

然后调用武器.dmg,但这是行不通的,因为它认为我正在尝试调用武器.dmg,而不是wp1.dmg


//players base damage
int damage = 0;

//players strength attribute
int strength = 0;

//weapon constructor
class wp
        {
            public int dmg;
            public int cost;
            public string name;

            public wp(int d, int c, string n)
            {
                dmg = d;
                cost = c;
                name = n;
            }
        }

//three weapons that are constructed
wp wp1 = new wp(1, 25, "dg");
wp wp2 = new wp(3, 100, "ss");
wp wp3 = new wp(5, 250, "ls");

//the current weapon string
public string weapon = "wp1";

void attack()
{
   //calculates damage based off of the players damage, strength, and weapon
   int newDamage = damage * strength + (weapon.dmg);
}
Run Code Online (Sandbox Code Playgroud)

预期结果: 程序应使用玩家当前武器的伤害值

实际结果是程序尝试查找武器的dmg值,但这是不可能的,因为“武器”只是一个字符串,因此会引发错误

Eri*_*ert 6

就像我在上面的评论中说的,作为一个初学者现在就养成良好的习惯,以后您就不必改变这些习惯了。让我们看看我们如何设计您的系统。从设计良好的类层次结构开始。假设我们有三种武器:剑,匕首和棍棒。他们共有的东西进入了一个抽象基类:

abstract class Weapon
{
Run Code Online (Sandbox Code Playgroud)

他们有什么共同点?损坏,费用和名称。因此,请为这些对象创建抽象的只读属性:

    public abstract int Damage { get; }
    public abstract decimal Cost { get; }
    public abstract string Name { get; }
}
Run Code Online (Sandbox Code Playgroud)

现在创建一些派生类。您是否打算进一步扩展它们?如果没有,请密封它们:

sealed class Sword : Weapon 
{
    public override int Damage => 10;
    public override decimal Cost => 12.5m;
    public override string Name => "normal sword";
}
Run Code Online (Sandbox Code Playgroud)

等等。

现在为玩家做同样的事情。假设我们可以更改玩家的武器,但不能更改其名称。因此Name应为只读属性,并且Weapon应为读写属性:

sealed class Player
{
  public string Name { get; private set; }
  public Weapon Weapon { get; set; }
  public int Strength { get; private set; }
  public int BaseDamage { get; private set; }
  public Player(string name, Weapon weapon, int strength, int baseDamage)
  {
    this.Name = name;
    this.Weapon = weapon;
    this.Strength = strength;
    this.BaseDamage = baseDamage;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以制造一些武器:

Weapon weapon1 = new Sword();
Weapon weapon2 = new Dagger();
Weapon weapon3 = new Club();
Player fighter = new Player("Bob", weapon3, 5, 10);
Run Code Online (Sandbox Code Playgroud)

或更好:

var weapons = new List<Weapon> { new Sword(), new Dagger(), new Club() };
// weapons is indexed 0, 1, 2.
Player fighter = new Player("Bob", weapons[2], 5, 10);
Run Code Online (Sandbox Code Playgroud)

现在,如果您有一个播放器在手:

static void Attack(Player p)
{
  int damage = p.BaseDamage * p.Strength + p.Weapon.Damage;
  string text = $"Player {p.Name} attacks with {p.Weapon.Name}";
Run Code Online (Sandbox Code Playgroud)

没有用于引用对象的字符串!除文本外,请勿将字符串用于任何其他内容。对对象的引用应该是对对象的引用,而不是字符串。

现在,仅对于高级玩家,有时您确实需要按字符串查找内容。在C#中执行此操作的方式是:

var d = new Dictionary<string, Weapon> {
  { "weapon1", new Sword() },
  { "weapon2", new Dagger() },
  { "weapon3", new Club() } 
};
Weapon w = d["weapon1"]; // w is a Sword.
Run Code Online (Sandbox Code Playgroud)

但是默认情况下不要这样做。这不是在C#中引用某些东西的正常方法。