【问题标题】:Best way to write multiple constructor overloads in C#在 C# 中编写多个构造函数重载的最佳方法
【发布时间】:2020-05-06 21:50:11
【问题描述】:

我正在学习 C# 并制作了一个简单的“播放器”类。但我很难有多重超载。 这是我最好的解决方案,但我觉得它可以做得更简单/更好。

class Player : Entity
    {
        public Player() {
            Name = "Player";
            XP = 0;
            LVL = 1;
            XPToLvlUp = 10;
            XpRank = 10;
        }

        public Player(string name) : this() {
            Name = name;
        }

        public Player(string name, int _Hp, int _Mp) : this(name) {
            HP = _Hp;
            MP = _Mp;
        }

        public Player(string name, int _Hp, int _Mp, int _Xp, int _Lvl) : this(name, _Hp, _Mp) {
            XP = _Xp;
            LVL = _Lvl;
        }

        public Player(string name, int _Hp, int _Mp, int _Xp, int _Lvl, int XpByRank) : this(name, _Hp, _Mp, _Xp, _Lvl) {
            XpRank = XpByRank;
        }

        //deleted code for better reading

        private int XPToLvlUp;
        private int XpRank;
        public int XP;
        public int LVL;
        public string Name;
    }  

好不好,如果不好请告诉我为什么。 感谢您的回复!

【问题讨论】:

  • 我觉得不错。如果你感觉不好,你应该说明为什么这看起来不好,也许最好理解你的疑虑。
  • 添加@user8276908 评论:您是否有理由要使用特定的构造函数而不是只使用一个?

标签: c# class constructor-overloading


【解决方案1】:

我认为这很好。要问自己一个问题:这些方法中的每一个是否真的可能被调用?

一种选择是让程序员在实例化类后设置这些值:

var myPlayer = new Player();
myPlayer.XP = 5;

但是,在某些情况下,您确实需要预先了解所有信息,因此这可能不合适。

另一个选项可能是传递给ctor的选项类:

public class PlayerSettings
{
  public Name = "Player";
  public XP = 0;
  public LVL = 1;
  public XPToLvlUp = 10;
  public XpRank = 10; 
}

那么你的 ctor 看起来像这样:

public Player() : this(new PlayerSettings())
{
}

public Player(PlayerSettings settings)
{
  //Fill in appropriate variables here
}

该选项将以这种方式调用:

var playerSettings = new PlayerSettings() { XP = 5 };
var myPlayer = new Player(playerSettings());

最后,我不确定一个是否比另一个“更好”,这在很大程度上取决于您的需求。

【讨论】:

    【解决方案2】:

    你的课几乎很好并且可以接受。

    小故事:使用属性。

    长篇大论:

    首先制定或遵循命名规则,它会让你的代码更易于阅读。这取决于你,只是一个建议。对于由多个单词组成的复杂名称,您可以使用CamelCasedNames。并避免在可能有用的地方缩短所有类型数据的名称。例如,您可以将 Lvl 扩展为 Level,但将 Xp 扩展为 Experience 会看起来很奇怪。这也取决于你。

    string name; // local Variable, first character lower cased
    private string _name; // private Field, first character is lower cased with leading "_"
    public string Name { get; set; } // public Property, first character is upper cased
    

    我将向您展示替代构造函数的替代方法,并将遵循命名规则。

    1) 构造函数的默认值(为了简单起见,你的类的一部分)

    class Player
    {
        public Player(string name = "Player", int xp = 0, int level = 1)
        {
            Name = name;
            Xp = xp;
            Level = level;
        }
    
        // Properties instead of Fields
        public int Xp { get; private set; } // restrict modification of the property outside of a class but reading is available
        public int Level { get; private set; }
        public string Name { get; set; }
    } 
    

    2) 没有带有默认值的构造函数的属性

    第一个属性的目的是限制对数据的访问,以保持内部对象数据的一致性。即使你在代码中犯了错误。避免一些错误的好方法。

    第二个属性目的是在获取或设置代码时执行代码。例如,使属性相互依赖以存储更少且唯一的数据。

    class Player
    {
        public int Xp { get; private set; } = 0;
        public int Level { get; private set; } = 1;
        public string Name { get; set; } = "Player";
    } 
    

    用法

    Player player = new Player() { Name = "KillerPWNZ", Level = 100, Xp = 999999 };
    

    奖励:另一个属性功能

    您可以执行getset 子句中的任何代码。

    假设每个下一个玩家的级别需要双倍的经验值,但第二级需要 100 经验值。你决定向第一级玩家开具 1000 XP 的发票。显然你需要敲几次Level。假设Xp 包含相对于Level 的值。

    发票

    player.Xp += 1000;
    

    带有代码的属性

    private int _xp = 0;
    
    public int Level { get; private set; } = 1;
    public int Xp
    {
        get => _xp; // same as: get { return _xp; }
        set
        {
            _xp = value; // here value is keyword containing data you want to set
            while (_xp >= GetXpPerLevel(Level))
            {
                _xp -= GetXpPerLevel(Level);
                Level++;
            }
            while (_xp < 0 && Level > 1)
            {
                _xp += GetXpPerLevel(Level - 1);
                Level--;
            }
        }
    }
    
    // helper method
    private int GetXpPerLevel(int level)
    {
        if (level < 1) return 0;
    
        // int result = 100;
        // for (int i = 1; i < level; i++) result *= 2;
        // return result;
    
        // or the same with some binary shift magic :)
        return 100 << (level - 1);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-09
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      相关资源
      最近更新 更多