Unity C#编程优化——枚举
我讨厌C#的枚举类型。我都会尽量避免它。考虑下面关于行星枚举的这个例子:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
|
public
enum
Planet {
MERCURY,
VENUS,
EARTH,
MARS,
JUPITER,
SATURN,
URANUS,
NEPTUNE,
PLUTO
// Pluto is a planet!!!
}
|
起初,这样的定义还算好,直到需要产生一个行星的质量。所以我们做这样的事情:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// Returns the mass of the planet in 10^24 kg
public
float
GetMass(Planet planet) {
switch
(planet) {
case
Planet.MERCURY:
return
0.330;
case
Planet.VENUS:
return
4.87f;
case
Planet.EARTH:
return
5.97f;
...
case
Planet.PLUTO:
return
0.0146f;
}
}
|
行星直径又如何? 另一个switch语句? 密度怎么样? 重力? 逃跑速度? 只要想想你将要维护的switch语句的数量。 你可以争辩说,你可以使用一个Dictionary,但仍然笨重。 每个数据的Dictionary都要映射?没门。
有一个更好的方法,我会告诉你如何。 这可能已经是非Unity程序员的常识,但我想在我的博客中再次提出这个冗余的主题,对于那些可能不知道这一点的人来说,特别是初学者。 我也想保持简单。
基本上,你可以使用类作为枚举。 为什么用类? 这确实表现的更好 您可以存储任意数量的任意数据。 您甚至可以存储例程或功能。 你可以做很多事情。 唯一的要求是它是不可变的,这意味着类一个实例的状态在整个程序期间都不能改变。以下是Planet枚举用类表示的一个版本:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public
class
Planet {
// The different values
public
static
readonly
Planet MERCURY =
new
Planet(0, 0.330f, 4879, 5427, 3.7f);
public
static
readonly
Planet VENUS =
new
Planet(1, 4.87f, 12104, 5243, 8.9f);
public
static
readonly
Planet EARTH =
new
Planet(2, 5.97f, 12756, 5514, 9.8f);
public
static
readonly
Planet MARS =
new
Planet(3, 0.642f, 6792, 3933, 3.7f);
public
static
readonly
Planet JUPITER =
new
Planet(4, 1898.0f, 142984, 1326, 23.1f);
public
static
readonly
Planet SATURN =
new
Planet(5, 568.0f, 120536, 687, 9.0f);
public
static
readonly
Planet URANUS =
new
Planet(6, 86.8f, 51118, 1271, 8.7f);
public
static
readonly
Planet NEPTUNE =
new
Planet(7, 102.0f, 49528, 1638, 11.0f);
public
static
readonly
Planet PLUTO =
new
Planet(8, 0.0146f, 2370, 2095, 0.7f);
// Use readonly to maintain immutability
private
readonly
int
id;
private
readonly
float
mass;
// in 10^24 kg
private
readonly
int
diameter;
// in km
private
readonly
int
density;
// in kg/m^3
private
readonly
float
gravity;
// in m/s^2
// We use a private constructor because this should not be instantiated
// anywhere else.
private
Planet(
int
id,
float
mass,
int
diameter,
int
density,
float
gravity) {
this
.id = id;
this
.mass = mass;
this
.diameter = diameter;
this
.density = density;
this
.gravity = gravity;
}
public
int
Id {
get
{
return
id;
}
}
public
float
Mass {
get
{
return
mass;
}
}
public
int
Diameter {
get
{
return
diameter;
}
}
public
int
Density {
get
{
return
density;
}
}
public
float
Gravity {
get
{
return
gravity;
}
}
}
|
为了保持不变性,所有成员变量应该是只读的。 一旦他们被分配,他们将不能再被改变。 这很重要,因为作为枚举,它的内部值不应该改变。 然后将每个枚举值实现为该类的静态只读实例。
这是怎么用的? 与正常枚举是一样的,如下使用:
[C#]
纯文本查看
复制代码
1
2
3
4
5
|
// Use it like an enum
ship.TargetPlanet = Planet.NEPTUNE;
// Want to know the target planet's mass?
float
mass = ship.TargetPlanet.Mass;
// Density?
int
density = ship.TargetPlanet.Density;
|
我们已经消除了切换语句或字典来维护不同行星信息的需要。 想要一个新的行星状态? 只需添加一个新的成员变量并在实例化上指定它们。
如何从其他数据类型转换? 喜欢说从int id转换为Planet实例? 这很容易 通常我为这些转换添加了一个公共和静态方法。 例如:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public
class
Planet {
// The different values
public
static
readonly
Planet MERCURY =
new
Planet(0, 0.330f, 4879, 5427, 3.7f);
public
static
readonly
Planet VENUS =
new
Planet(1, 4.87f, 12104, 5243, 8.9f);
public
static
readonly
Planet EARTH =
new
Planet(2, 5.97f, 12756, 5514, 9.8f);
public
static
readonly
Planet MARS =
new
Planet(3, 0.642f, 6792, 3933, 3.7f);
public
static
readonly
Planet JUPITER =
new
Planet(4, 1898.0f, 142984, 1326, 23.1f);
public
static
readonly
Planet SATURN =
new
Planet(5, 568.0f, 120536, 687, 9.0f);
public
static
readonly
Planet URANUS =
new
Planet(6, 86.8f, 51118, 1271, 8.7f);
public
static
readonly
Planet NEPTUNE =
new
Planet(7, 102.0f, 49528, 1638, 11.0f);
public
static
readonly
Planet PLUTO =
new
Planet(8, 0.0146f, 2370, 2095, 0.7f);
// This can be used to loop through all planets
public
static
Planet[] ALL =
new
Planet[] {
MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE, PLUTO
};
// Converts the specified id to a Planet instance
public
static
Planet Convert(
int
id) {
for
(
int
i = 0; i < ALL.Length; ++i) {
if
(ALL.Id == id) {
return
ALL;
}
}
// return ALL[id] could also work here but what if a non sequential id is used?
throw
new
Exception(
"Cannot convert {0} to a Planet."
.FormatWith(id));
}
...
}
// Usage
Planet planet = Planet.Convert(someIntPlanet);
|
想从字符串ID转换? 添加将保存此值的字符串成员变量。 而不是使用诸如ALL []的数组,您可以使用如下所示的Dictionary:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
|
private
static
Dictionary<
string
, Planet> ALL =
new
Dictionary<
string
, Planet>() {
{ MERCURY.TextId, MERCURY },
{ VENUS.TextId, VENUS },
{ EARTH.TextId, EARTH },
...
{ PLUTO.TextId, PLUTO },
};
// Converts the specified string to a Planet instance
public
static
Planet Convert(
string
id) {
return
ALL[id];
}
|
您可以支持您喜欢的任何类型的转换。
还有更多的你可以做。 您现在可以添加功能。 你可以这样做:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
Planet currentPlanet = Planet.VENUS;
currentPlanet.ApplyGravity(ship);
The coolest thing
for
me
is
you can specify different actions or behavior to the
enum
values. Something like
this
(It’s very contrived but you
get
the idea.):
public
static
readonly
Planet EARTH =
new
Planet(2, 5.97f, 12756, 5514, 9.8f,
delegate
(Ship ship) {
// Actions on land of ship
ship.AddFood(1000);
ship.RetireCrew();
ship.RecruitNewCrew();
});
public
static
readonly
Planet MARS =
new
Planet(3, 0.642f, 6792, 3933, 3.7f,
delegate
(Ship ship) {
// Actions on land of ship
ship.DeductFood(50);
ship.Research();
ship.Mine();
});
|
通过简单地将你的枚举变成一个类,你已经将它升级到更有组织的东西,而且更加功能强大。 您也可以使用反射和继承等先进功能,但大多数情况下,您不需要。
希望这可以帮助你。