在 C# 中编写多个构造函数重载的最佳方法
Best way to write multiple constructor overloads in C#
正在学习C#,做了个简单的"Player"class。但我很难承受多重超载。
这是我最好的解决方案,但我觉得可以做到 simpler/better。
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;
}
它好吗,如果不好请告诉我为什么。
感谢您的回复!
我觉得这样很好。有一个问题要问自己:这些方法中的每一个实际上都可能被调用吗?
一种选择是让程序员在实例化 class:
之后设置这些值
var myPlayer = new Player();
myPlayer.XP = 5;
但是,在某些情况下,您确实需要预先了解所有信息,因此这可能并不合适。
另一个选项可以是传递给 ctor 的选项 class:
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());
最后,我不确定一个比另一个"better",这在很大程度上取决于您的需求。
您的 class 几乎可以接受。
短篇小说: 使用属性。
长话短说:
首先制定或遵循命名规则,它会让你的代码更易于阅读。这取决于你,只是一个建议。对于由多个单词组成的复杂名称,您可以使用 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 的一部分以保持简单)
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
子句中的任何代码。
让我们假设下一个玩家的等级需要双倍的 xp,但第 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);
}
正在学习C#,做了个简单的"Player"class。但我很难承受多重超载。 这是我最好的解决方案,但我觉得可以做到 simpler/better。
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;
}
它好吗,如果不好请告诉我为什么。 感谢您的回复!
我觉得这样很好。有一个问题要问自己:这些方法中的每一个实际上都可能被调用吗?
一种选择是让程序员在实例化 class:
之后设置这些值var myPlayer = new Player();
myPlayer.XP = 5;
但是,在某些情况下,您确实需要预先了解所有信息,因此这可能并不合适。
另一个选项可以是传递给 ctor 的选项 class:
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());
最后,我不确定一个比另一个"better",这在很大程度上取决于您的需求。
您的 class 几乎可以接受。
短篇小说: 使用属性。
长话短说:
首先制定或遵循命名规则,它会让你的代码更易于阅读。这取决于你,只是一个建议。对于由多个单词组成的复杂名称,您可以使用 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 的一部分以保持简单)
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
子句中的任何代码。
让我们假设下一个玩家的等级需要双倍的 xp,但第 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);
}