Лучший способ написать несколько перегрузок конструктора в C# - PullRequest
2 голосов
/ 07 мая 2020

Я изучаю 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;
    }  

Это хорошо, и если нет, скажите, почему. Спасибо за ответы!

Ответы [ 2 ]

5 голосов
/ 07 мая 2020

Думаю, все в порядке. Один вопрос, который стоит задать себе: действительно ли вероятен вызов каждого из этих методов?

Один из вариантов - просто позволить программисту установить эти значения после того, как они создали экземпляр класса:

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; 
}

Тогда ваши ctors выглядят так:

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());

В конце концов, я не уверен, что один из них «лучше» чем другие, это во многом зависит от ваших потребностей.

4 голосов
/ 07 мая 2020

Ваш класс почти хороший и приемлемый.

Краткий рассказ: используйте свойства.

Длинный рассказ:

Прежде всего составьте или соблюдайте правила именования, это сделает ваш код более удобным для чтения. Это зависит от вас, просто предложение. Для сложных имен, состоящих из нескольких слов, вы можете использовать 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 };

Бонус: Другая функция свойства

Вы можете выполнить любой код в предложении get или set.

Предположим, что для каждого следующего уровня игрока требуется удвоенное количество опыта по сравнению с предыдущим, но 2-й уровень требует 100 XP. И вы решили выставить счет игроку 1-го уровня на 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...