关于枚举的种种 (Enumeration FAQ) [C#, IL, BCL]
2009-02-02 03:34
399 查看
原文 http://www.cnblogs.com/allenlooplee/archive/2004/12/19/70230.html
Q:在C#里,我们如何表达枚举类型?
A:你可以使用enum关键字(keyword)来声明一个枚举类型(enum type):
// Code #01
public enum Alignment
// Code #02
.class public auto ansi sealed Aligment
extends [mscorlib]System.Enum
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
请注意,.NET Framework SDK v2.0.3600.0 Documentation中的Enum声明是错的:
public abstract struct Enum : IComparable, IFormattable, IConvertible
Q:开始头晕了 // Code #04
static void Main()
// Code #05
// See Code #01 for Alignment.
static void Main()
// Code #06
.method private hidebysig static void Main() cil managed
// Code #07
// See Code #01 for Alignment.
class Program
// Code #08
.method private hidebysig static void Main(string[] args) cil managed
.field public static literal Aligment Center = int32(0x00000001)
该语句明显是整数赋值,这是否说明枚举类型实质上是整数类型?
A:这说明枚举类型与整数类型的确有一定的关系。事实上,每一个枚举类型都有与之相对应的整数类型,我们称该整数类型为底层类型(underlying type),默认的情况下使用,.NET使用System.Int32。当然,你可以手动将其指定为其他的整数类型:
// Code #09
public enum Alignment : byte
// Code #10
public enum Alignment
// Code #11
public enum DriveType : sbyte
public static Array GetValues(Type enumType);
该方法返回一个包含所有枚举成员的数组:
// Code #12
// See Code #01 for Alignment.
public static void Main()
// Output:
// Wanna see the values of Alignment's menbers?
// Left = 0
// Center = 1
// Right = 2
Q:如果我只需要其中某些枚举成员的值呢?
A:那么你可以把枚举转换为IConvertible接口,再调用对应的方法:
// Code #12
// See Code #01 for Alignment.
public static void Main()
// Output:
// The value of Alignment.Center is 1.
Q:为什么需要手动指定枚举成员的值?
A:一般情况下,使用默认的赋值规则就足够了,但某些情况下,为枚举成员指定一个与实际情况(模型)相符的值可能更有意义,这要视你具体所建的模型而定。
还是让我们来一个实际的例子:
// Code #13
public enum CustomerKind
public class Customer
// Code #14
// See Code #01 for Alignment.
Alignment a = (Alignment)1;
但这种机制可能使你遇到一些麻烦:
// Code #15
// See Code #01 for Alignment.
class Program
public static bool IsDefined(Type enumType, object value);
现在我们把Code #15的Foo方法改进一下:
// Code #16
// See Code #01 for Alignment.
static void Foo(Alignment a)
// Code #17
// See Code #01 for Alignment.
static void Foo(Alignment a)
// Code #18
// See Code #01 for Alignment.
static void Foo(Alignment a)
// Code #19
// See Code #01 for Alignment.
public static bool IsAlignment(Alignment a)
// Code #20
public enum FontStyle
// Code #21
// I am using the FlagsAttribute to identify a bit flags.
[Flags]
public enum FontStyle
// Code #22
// See Code #21 for FontStyle.
Font f = new Font(
FontFamily.GenericSansSerif,
12.0F,
FontStyle.Italic | FontStyle.Underline
);
Q:位枚举同样存在类似于Code #15的恶作剧吧?
A:是的,例如:
// Code #23
// See Code #21 for FontStyle.
class Program
// Code #24
// See Code #21 for FontStyle.
FontStyle fs1 = FontStyle.Bold | FontStyle.Italic | FontStyle.Underline;
Console.WriteLine(Enum.IsDefine(typeof(FontStyle), fs1));
FontStyle fs2 = FontStyle.Regular | (FontStyle)0x0400;
Console.WriteLine(Enum.IsDefine(typeof(FontStyle), fs2));
// Output:
// false
// false
我们对代码的输出毫无疑问,因为fs1和fs2都不是一个单独的枚举成员。但这不是我们所追求的答案,我们希望区别对待fs1和fs2,至少我们不希望fs2中的捣蛋家伙——(FontStyle)0x0400——在我们的程序中搞破坏!
Q:那么,我们是否有办法隔离这些捣蛋鬼呢?
A:Of course!我们同样可以使用条件判断语句来处理,但做法将与Code #17和Code #18有所不同。现在我们把Code #23改进如下:
// Code #25
// See Code #21 for FontStyle.
class Program
// Code #26
// See Code #21 for FontStyle.
static bool ContainsBold(FontStyle fs)
static bool ContainsItalic(FontStyle fs)
// Other similar methods continue here
又或者你可以写一个这样的方法:
// Code #27
// See Code #21 for FontStyle.
static bool ContainsMember(FontStyle fs, FontStyle menber)
// Code #28
// See Code #21 for FontStyle.
static bool ContainsPranksters(FontStyle fs)
// Code #35
[Flags]
enum Music
static void Main()
// Code #36
[Flags]
enum Music
public override string ToString();
方法,或者把枚举类型转换为IConvertible接口,再调用该接口的
string ToString(IFormatProvider provider);
方法。此时你将得到枚举成员的字面值的字符串:
// Code #29
// See Code #01 for Alignment.
// See Code #21 for FontStyle.
static void Main()
// Output:
// Alignment is Right.
// FontStyle is Bold, Underline.
如果你希望输出枚举成员的值,那么你可以手动指定格式参数:
// Code #30
// See Code #01 for Alignment.
// See Code #21 for FontStyle.
static void Main()
// Output:
// Alignment is 2.
// Alignment is 00000002.
// FontStyle is 33.
// FontStyle is 00000021.
除此之外,你还可以使用System.Enum的
public static string Format(
Type enumType,
object value,
string format
);
方法:
// Code #31
// See Code #01 for Alignment.
static void Main()
// Output:
// Alignment is 0x00000002.
// Alignment is 0x00000002.
另外,你还可以通过System.Enum的
public static string[] GetNames(Type enumType);
来获取枚举所有成员的字面值:
// Code #32
// See Code #01 for Alignment.
static void Main()
// Output:
// Left
// Center
// Right
Q:如果我得到一个表示枚举成员的字符串,我如何将其解析为对应枚举类型呢?
A:这时你就需要System.Enum的
public static object Parse(
Type enumType,
string value,
bool ignoreCase
);
方法了:
// Code #33
// See Code #01 for Alignment.
// See Code #21 for FontStyle.
static void Main()
// Output:
// Right
// Bold, Italic, Underline
Q:枚举类型为我们编码提供了巨大的便利,什么情况下我们不应该使用枚举呢?
A:首先你应该清楚枚举类型在编程中充当一个什么样的角色。在我看来,枚举类型表达了一种稳定的分类标准。当你查看.NET Framework BCL中的枚举类型,你会发现它们几乎没有任何改变的可能或者趋势,表现出一种稳定性。所以,当你所要表达的分类标准也同样具备这种稳定性时,你就可以考虑枚举类型了。那么什么情况下不使用枚举呢?一般说来,当分类标准不闭合时——即新的子分类随时有可能产生或者现有子分类随时有可能被替换——你就应该考虑使用其他的方式来表达了。
下面让我们来看一个薪酬自动管理系统的一部分,假设某公司现有雇员种类为:
1. Programmer
2. Salesman
3. Manager
相关代码如下:
// Code #34
public enum EmployeeKind
public class Employee
{
public Employee(string name, EmployeeKind kind)
{
Kind = kind;
}
private string m_Name;
public string Name
{
get { return m_Name; }
}
public readonly EmployeeKind Kind;
public double GetPayment()
{
switch(Kind)
{
case EmployeeKind.Programmer:
// Return payment
case EmployeeKind.Salesman:
// Return payment
case EmployeeKind.Manager:
// Return payment
}
}
}
假如该公司正处于成长期,那么公司的组织结构发生改变是家常便饭之事。但公司每一次改变组织结构,这样的系统就要经历源代码修改、重新编译然后再部署的过程!而且,如果公司实行了新的绩效评估方案,并把薪酬计算与绩效追踪挂钩,那么GetPayment方法将进一步壮大,以至于最终其代码晦涩难懂。你当然可以把GetPayment分割为子方法,但并没有什么实质的改变。再想一想,如果将来公司打算把薪酬系统与银行挂钩,提供薪资直接银行划拨,那将又会是怎么一番局面呢?
好吧,我承认我不太愿意接手维护这样的系统
,但讨论如何改进这个系统会使本文进一步壮大,以至于最终其内容晦涩难懂
,不过你应该可以从我的《今天你多态了吗?》中找到一些改进灵感。
Q:在C#里,我们如何表达枚举类型?
A:你可以使用enum关键字(keyword)来声明一个枚举类型(enum type):
// Code #01
public enum Alignment
// Code #02
.class public auto ansi sealed Aligment
extends [mscorlib]System.Enum
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
请注意,.NET Framework SDK v2.0.3600.0 Documentation中的Enum声明是错的:
public abstract struct Enum : IComparable, IFormattable, IConvertible
Q:开始头晕了 // Code #04
static void Main()
// Code #05
// See Code #01 for Alignment.
static void Main()
// Code #06
.method private hidebysig static void Main() cil managed
// Code #07
// See Code #01 for Alignment.
class Program
// Code #08
.method private hidebysig static void Main(string[] args) cil managed
.field public static literal Aligment Center = int32(0x00000001)
该语句明显是整数赋值,这是否说明枚举类型实质上是整数类型?
A:这说明枚举类型与整数类型的确有一定的关系。事实上,每一个枚举类型都有与之相对应的整数类型,我们称该整数类型为底层类型(underlying type),默认的情况下使用,.NET使用System.Int32。当然,你可以手动将其指定为其他的整数类型:
// Code #09
public enum Alignment : byte
// Code #10
public enum Alignment
// Code #11
public enum DriveType : sbyte
public static Array GetValues(Type enumType);
该方法返回一个包含所有枚举成员的数组:
// Code #12
// See Code #01 for Alignment.
public static void Main()
// Output:
// Wanna see the values of Alignment's menbers?
// Left = 0
// Center = 1
// Right = 2
Q:如果我只需要其中某些枚举成员的值呢?
A:那么你可以把枚举转换为IConvertible接口,再调用对应的方法:
// Code #12
// See Code #01 for Alignment.
public static void Main()
// Output:
// The value of Alignment.Center is 1.
Q:为什么需要手动指定枚举成员的值?
A:一般情况下,使用默认的赋值规则就足够了,但某些情况下,为枚举成员指定一个与实际情况(模型)相符的值可能更有意义,这要视你具体所建的模型而定。
还是让我们来一个实际的例子:
// Code #13
public enum CustomerKind
public class Customer
// Code #14
// See Code #01 for Alignment.
Alignment a = (Alignment)1;
但这种机制可能使你遇到一些麻烦:
// Code #15
// See Code #01 for Alignment.
class Program
public static bool IsDefined(Type enumType, object value);
现在我们把Code #15的Foo方法改进一下:
// Code #16
// See Code #01 for Alignment.
static void Foo(Alignment a)
// Code #17
// See Code #01 for Alignment.
static void Foo(Alignment a)
// Code #18
// See Code #01 for Alignment.
static void Foo(Alignment a)
// Code #19
// See Code #01 for Alignment.
public static bool IsAlignment(Alignment a)
// Code #20
public enum FontStyle
// Code #21
// I am using the FlagsAttribute to identify a bit flags.
[Flags]
public enum FontStyle
// Code #22
// See Code #21 for FontStyle.
Font f = new Font(
FontFamily.GenericSansSerif,
12.0F,
FontStyle.Italic | FontStyle.Underline
);
Q:位枚举同样存在类似于Code #15的恶作剧吧?
A:是的,例如:
// Code #23
// See Code #21 for FontStyle.
class Program
// Code #24
// See Code #21 for FontStyle.
FontStyle fs1 = FontStyle.Bold | FontStyle.Italic | FontStyle.Underline;
Console.WriteLine(Enum.IsDefine(typeof(FontStyle), fs1));
FontStyle fs2 = FontStyle.Regular | (FontStyle)0x0400;
Console.WriteLine(Enum.IsDefine(typeof(FontStyle), fs2));
// Output:
// false
// false
我们对代码的输出毫无疑问,因为fs1和fs2都不是一个单独的枚举成员。但这不是我们所追求的答案,我们希望区别对待fs1和fs2,至少我们不希望fs2中的捣蛋家伙——(FontStyle)0x0400——在我们的程序中搞破坏!
Q:那么,我们是否有办法隔离这些捣蛋鬼呢?
A:Of course!我们同样可以使用条件判断语句来处理,但做法将与Code #17和Code #18有所不同。现在我们把Code #23改进如下:
// Code #25
// See Code #21 for FontStyle.
class Program
// Code #26
// See Code #21 for FontStyle.
static bool ContainsBold(FontStyle fs)
static bool ContainsItalic(FontStyle fs)
// Other similar methods continue here
又或者你可以写一个这样的方法:
// Code #27
// See Code #21 for FontStyle.
static bool ContainsMember(FontStyle fs, FontStyle menber)
// Code #28
// See Code #21 for FontStyle.
static bool ContainsPranksters(FontStyle fs)
// Code #35
[Flags]
enum Music
static void Main()
// Code #36
[Flags]
enum Music
public override string ToString();
方法,或者把枚举类型转换为IConvertible接口,再调用该接口的
string ToString(IFormatProvider provider);
方法。此时你将得到枚举成员的字面值的字符串:
// Code #29
// See Code #01 for Alignment.
// See Code #21 for FontStyle.
static void Main()
// Output:
// Alignment is Right.
// FontStyle is Bold, Underline.
如果你希望输出枚举成员的值,那么你可以手动指定格式参数:
// Code #30
// See Code #01 for Alignment.
// See Code #21 for FontStyle.
static void Main()
// Output:
// Alignment is 2.
// Alignment is 00000002.
// FontStyle is 33.
// FontStyle is 00000021.
除此之外,你还可以使用System.Enum的
public static string Format(
Type enumType,
object value,
string format
);
方法:
// Code #31
// See Code #01 for Alignment.
static void Main()
// Output:
// Alignment is 0x00000002.
// Alignment is 0x00000002.
另外,你还可以通过System.Enum的
public static string[] GetNames(Type enumType);
来获取枚举所有成员的字面值:
// Code #32
// See Code #01 for Alignment.
static void Main()
// Output:
// Left
// Center
// Right
Q:如果我得到一个表示枚举成员的字符串,我如何将其解析为对应枚举类型呢?
A:这时你就需要System.Enum的
public static object Parse(
Type enumType,
string value,
bool ignoreCase
);
方法了:
// Code #33
// See Code #01 for Alignment.
// See Code #21 for FontStyle.
static void Main()
// Output:
// Right
// Bold, Italic, Underline
Q:枚举类型为我们编码提供了巨大的便利,什么情况下我们不应该使用枚举呢?
A:首先你应该清楚枚举类型在编程中充当一个什么样的角色。在我看来,枚举类型表达了一种稳定的分类标准。当你查看.NET Framework BCL中的枚举类型,你会发现它们几乎没有任何改变的可能或者趋势,表现出一种稳定性。所以,当你所要表达的分类标准也同样具备这种稳定性时,你就可以考虑枚举类型了。那么什么情况下不使用枚举呢?一般说来,当分类标准不闭合时——即新的子分类随时有可能产生或者现有子分类随时有可能被替换——你就应该考虑使用其他的方式来表达了。
下面让我们来看一个薪酬自动管理系统的一部分,假设某公司现有雇员种类为:
1. Programmer
2. Salesman
3. Manager
相关代码如下:
// Code #34
public enum EmployeeKind
public class Employee
{
public Employee(string name, EmployeeKind kind)
{
Kind = kind;
}
private string m_Name;
public string Name
{
get { return m_Name; }
}
public readonly EmployeeKind Kind;
public double GetPayment()
{
switch(Kind)
{
case EmployeeKind.Programmer:
// Return payment
case EmployeeKind.Salesman:
// Return payment
case EmployeeKind.Manager:
// Return payment
}
}
}
假如该公司正处于成长期,那么公司的组织结构发生改变是家常便饭之事。但公司每一次改变组织结构,这样的系统就要经历源代码修改、重新编译然后再部署的过程!而且,如果公司实行了新的绩效评估方案,并把薪酬计算与绩效追踪挂钩,那么GetPayment方法将进一步壮大,以至于最终其代码晦涩难懂。你当然可以把GetPayment分割为子方法,但并没有什么实质的改变。再想一想,如果将来公司打算把薪酬系统与银行挂钩,提供薪资直接银行划拨,那将又会是怎么一番局面呢?
好吧,我承认我不太愿意接手维护这样的系统
,但讨论如何改进这个系统会使本文进一步壮大,以至于最终其内容晦涩难懂
,不过你应该可以从我的《今天你多态了吗?》中找到一些改进灵感。
相关文章推荐
- 关于枚举的种种 (Enumeration FAQ) [C#, IL, BCL]
- 关于枚举的种种 (Enumeration FAQ) [C#, IL, BCL]
- 关于枚举的种种 (Enumeration FAQ) [C#, IL, BCL] (转)
- 关于枚举的种种 [C#, IL, BCL]
- 关于PHP操作文件的一些FAQ总结
- 关于做PDF的FAQ(一)~(四)
- 黑马程序员关于常量、枚举、结构的复习
- 关于Mysql数据库longblob格式数据的插入com.mysql.jdbc.PreparedStatement.setBinaryStream(ILjava/io/InputStream;J)V问题分析
- 关于linux编程的奇淫巧计系列的FAQ
- 关于Flash Player10 RTMFP的FAQ
- 黑马程序员——关于枚举
- StringCollection FAQ [C#, BCL]
- Java的一个关于“星球”的枚举
- 集合框架取出元素的方式(二)Enumeration枚举方式
- 关于枚举、反射、泛型的简单例子
- Java中vector的使用详解、enumeration枚举接口的和iterator的区别、vector与list的对比
- 关于枚举的用法和类型转换
- 关于枚举,你应该了解的东西
- piner整理的关于Oracle的 FAQ