`

枚举是值类型而System.Enum却是引用类型的原因

阅读更多


Q:在C#里,我们如何表达枚举类型?

A:你可以使用enum关键字(keyword)来声明一个枚举类型(enum type):

    // Code #01 
    public enum Alignment 
    { 
        Left, 
        Center, 
        Right 
    } 

--------------------------------------------------------------------------------
Q:C#枚举类型是值类型(value type)还是引用类型(reference type)?

A:枚举类型都是值类型。

--------------------------------------------------------------------------------

Q:System.Enum是枚举类型么?

A:不是。

--------------------------------------------------------------------------------

Q:System.Enum与枚举类型(enum type)有什么关系?

A:System.Enum是一个抽象类(abstract class),所有枚举类型都直接继承自它,当然也同时继承了它的所有成员。

--------------------------------------------------------------------------------

Q:那么System.Enum属于引用类型啦?

A:是的。

--------------------------------------------------------------------------------

Q:既然System.Enum是引用类型,而枚举类型又是直接继承自System.Enum的,那为什么枚举类型却不是引用类型?

A:这种继承关系是隐式的并由编译器负责展开,上面Code #1的Alignment枚举被展开后的IL代码如下:

    // Code #02 
    .class public auto ansi sealed Aligment 
           extends [mscorlib]System.Enum 
    { 
        .field public static literal Aligment Left = int32(0x00000000) 
        .field public static literal Aligment Center = int32(0x00000001) 
        .field public static literal Aligment Right = int32(0x00000002) 
    
        .field public specialname rtspecialname int32 value__ 
    } 

从声明中,你可以看到Aligment的确是继承自System.Enum的,只是你不能在C#里显式声明这种继承关系。

--------------------------------------------------------------------------------

Q:但你好像没有回答为什么枚举类型继承自一个引用类型后,却还是值类型!

A:你知道,所有的值类型都是System.ValueType的后代,枚举类型也不例外,枚举类型直接继承自System.Enum,而System.Enum却又直接继承自System.ValueType的,所以,枚举类型也是System.ValueType的后代。

--------------------------------------------------------------------------------

Q:慢着!从System.ValueType派生出来的类型不都应该是值类型吗?为什么System.Enum会是引用类型?

A:正确的说法应该是“值类型都是System.ValueType的后代”,但System.ValueType的后代不全是值类型,System.Enum就是唯一的特例!在System.ValueType的所有后代中,除了System.Enum之外其它都是值类型。事实上,我们可以在.NET的源代码中找到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:开始头晕了,究竟C#枚举类型、System.Enum、System.ValueType、值类型和引用类型之间存在着什么样的关系?

A:简单的说,

1. 所有枚举类型(enum type)都是值类型。
2. System.Enum和System.ValueType本身是引用类型。
3. 枚举类型(enum type)都是隐式的直接继承自System.Enum,并且这种继承关系只能由编译器自动展开。但System.Enum本身不是枚举类型(enum type)。
4. System.Enum是一个特例,它直接继承自System.ValueType(参见Code #03),但本身却是一个引用类型。
好吧,现在来看看下面代码,你能猜得出它的输出结果吗?

    // Code #04 
    static void Main() 
    { 
        Type t = typeof(System.Enum); 
    
        if (t.IsEnum) 
            Console.WriteLine("I'm enum type."); 
    
        if (t.IsValueType) 
            Console.WriteLine("I'm value type."); 
    } 

请别惊讶于程序的运行结果没有任何输出!对于第一个判断,我们很清楚System.Enum并不是枚举类型。但第二个判断呢?System.Enum明明继承自System.ValueType,却不承认是System.ValueType的后代!这是.NET上的一个特例,恰恰体现出System.Enum是特殊性。

--------------------------------------------------------------------------------

Q:既然枚举类型是值类型,自然会涉及到装箱和拆箱(boxing and unboxing)的问题,那么枚举类型会被装箱成什么呢?[Updated]

A:枚举类型可以被装箱成System.Enum、System.ValueType、System.Object或者System.IConvertible、System.IFormattable、System.IComparable。

注意:在.NET 1.1上,枚举类型只能被装箱到System.Enum、System.ValueType、System.Object;而在.NET 2.0上,枚举类型还能被装箱到System.Enum所实现的三个接口:System.IConvertible、System.IComparable、System.IFormattable。对应的装箱操作既可以为隐式的也可以是显式的。

下面的C#代码:

    // Code #05 
    // See Code #01 for Alignment. 
    static void Main() 
    { 
        Alignment a = Alignment.Center; 
    
        Console.WriteLine(a.ToString()); 
    
        Console.WriteLine(a); 
    } 

对应的IL代码是:

    // Code #06 
    .method private hidebysig static void Main() cil managed 
    { 
        .entrypoint 
        // Code Size: 32 byte(s) 
        .maxstack 1 
        .locals ( 
              EnumerationFaq.Alignment alignment1) 
        L_0000: ldc.i4.1  
        L_0001: stloc.0  
        L_0002: ldloc.0  
        L_0003: box EnumerationFaq.Alignment 
        L_0008: call instance string [mscorlib]System.Enum::ToString() 
        L_000d: call void [mscorlib]System.Console::WriteLine(string) 
        L_0012: nop  
        L_0013: ldloc.0  
        L_0014: box EnumerationFaq.Alignment 
        L_0019: call void [mscorlib]System.Console::WriteLine(object) 
        L_001e: nop  
        L_001f: ret  
    } 

从IL代码中我们可以看到枚举类型被装箱两次。第一次(L_0003)被装箱成System.Enum,而第二次(L_0014)就被装箱成System.Object。

但如果你让编译器自动为你选择装箱类型的话,它会优先考虑System.Enum:

    // Code #07 
    // See Code #01 for Alignment. 
    class Program 
    { 
        static void Main() 
        { 
            Alignment a = Alignment.Center; 
    
            Print(a); 
        } 
    
        static void Print(IConvertible c) 
        { 
            Console.WriteLine(c); 
        } 
    
        static void Print(IFormattable f) 
        { 
            Console.WriteLine(f); 
        } 
    
        static void Print(IComparable c) 
        { 
            Console.WriteLine(c); 
        } 
    
        static void Print(Object o) 
        { 
            Console.WriteLine(o); 
        } 
    
        static void Print(ValueType v) 
        { 
            Console.WriteLine(v); 
        } 
    
        static void Print(Enum e) 
        { 
            Console.WriteLine(e); 
        } 
    } 

上面的代码将被编译成如下的IL:

    // Code #08 
    .method private hidebysig static void Main(string[] args) cil managed 
    { 
        .entrypoint 
        // Code Size: 15 byte(s) 
        .maxstack 1 
        .locals ( 
              EnumerationFaq.Alignment alignment1) 
        L_0000: ldc.i4.1  
        L_0001: stloc.0  
        L_0002: ldloc.0  
        L_0003: box EnumerationFaq.Alignment 
        // 调用static void Print(Enum e); 
        L_0008: call void EnumerationFaq.Program::Print([mscorlib]System.Enum) 
        L_000d: nop  
        L_000e: ret  
    } 

声明:本文转载自http://www.cnblogs.com/cdts_change/archive/2009/09/20/1570414.html
分享到:
评论

相关推荐

    Java枚举类型Enum的用法

    Java枚举类型(Enum)是Java SE 5.0引入的一种新的数据类型,它为开发者提供了更为强大且安全的方式来表示一组常量。枚举在Java中不仅是一个类,还是一种特殊的类型,允许我们定义自己的常量集合。接下来,我们将...

    枚举类型的说明 enum

    枚举类型是一种特殊的类,实际上 enum 声明定义的类型就是一个类,这些类都是类库中 Enum 类的子类(java.lang.Enum)。它们继承了这个 Enum 中的许多有用的方法。 1、枚举类的特征 枚举类是特殊的类,其枚举值...

    javaenum(枚举)使用详解+总结.pdf

    Java中的枚举(enum)是自JDK 1.5版本引入的一种强大的类型,它用于定义一组相关的常量。枚举在Java中被设计为一种特殊的类,它们默认继承自`java.lang.Enum`抽象类,并且是单继承的,这意味着它们无法再继承其他类...

    枚举enum的一些案例

    枚举(enum)是一种特殊的值类型,它从 System.Enum 继承而来,并为基础的基元类型的值提供替代名称。枚举类型有名称、基础类型和一组字段。基础类型必须是一个内置的有符号(或无符号)整数类型(如 Byte、Int32 或...

    JAVA中的枚举类型1:基本用法.doc

    例如,可以通过枚举类型的名称来引用其成员之一: ```java Weekday wd = Weekday.MONDAY; ``` 这里将`Weekday`类型的变量`wd`赋值为`MONDAY`。由于枚举类型具有固定的成员集合,因此编译器会在编译阶段检查该枚举...

    高阶Java-Java枚举类型 enum 应用详解

    在Java编程语言中,枚举(enum)是一种特殊的类,用于定义一组固定的常量。它在许多场景下比使用常量或int类型的硬编码值更安全、更具可读性。本篇文章将深入探讨Java枚举的特性、用法以及如何在实际开发中充分利用...

    enum类型重定义解决方法

    这里的 `no_namespace` 选项告诉编译器不要将ADO的类型导入到全局命名空间,而 `rename` 指令则用于将 `EOF` 和 `BOF` 这两个枚举值重命名为 `adoEOF` 和 `adoBOF`,以此避免与MFC(Microsoft Foundation Classes)...

    java中enum枚举的详细用法

    Java中的枚举(enum)类型是在JDK 1.5版本引入的一个强大的特性,它用于定义一组相关的常量。在C/C++等语言中,枚举通常用来表示一组具有固定值的常量集合,但在Java中,枚举不仅限于此,它提供了更多的功能和灵活性...

    java枚举类型enum的使用

    ### Java 枚举类型 enum 的使用详解 #### 一、枚举类型概述 在 Java 中,枚举(enum)是一种特殊的类,它被用来表示一组固定的常量值。枚举类型自 JDK 1.5 开始引入,为开发者提供了一种更加安全、简洁的方式来...

    Java语言基础入门教程 Java实训教程 10.枚举与泛型 共27页.pptx

    - 枚举是一种引用类型,因为它隐式继承自`java.lang.Enum`类。 - 枚举是JDK 5.0之后新增的特性,使用并不频繁。 - 枚举值是常量,具有默认的`public static final`修饰符。 - 使用枚举类型的枚举变量赋值时可以直接...

    java 通过反射获取枚举类,及枚举类的值,枚举类枚举实例名

    枚举(Enumeration)是Java中的一个特殊类类型,用于定义一组常量。本项目"test-enum-demo-master"显然是一个用于演示如何通过反射来操作枚举类的示例。 首先,让我们理解枚举类的基本概念。枚举类在Java中用于定义...

    理解 C#值类型与引用类型.docx

    - **枚举(enum)**:基于整数的值类型,继承自`System.Enum`。 - **可空类型(nullable)**:使用`System.Nullable`泛型结构体表示可能为null的值类型。 值类型的关键特性是按值进行操作,这意味着复制一个值...

    C#中的枚举.doc

    C#中的枚举(Enum)是一种特殊的值类型,它允许我们定义一组相关的命名常量,这些常量在程序中代表特定的值。枚举在编程中广泛应用,因为它们提供了清晰的代码可读性,同时也避免了硬编码数字,使得代码更易于理解和...

    JAVA枚举类型的用法.doc

    - 在Java中,枚举类型通过`enum`关键字来定义。例如: ```java public enum Color { RED, GREEN, BLUE } ``` - 这里,`Color`是一个枚举类型,`RED`, `GREEN`, `BLUE`是它的三个枚举常量。 2. **枚举常量的...

    JAVA中的枚举类型2:高级特性.doc

    通过这种方式,我们可以在枚举类型中封装更多的业务逻辑,使得枚举不仅仅是一个简单的值容器。 ##### 方法重写实现多态 更进一步地,Java中的枚举类型支持方法重写,这使得我们可以实现某种程度上的多态行为。具体...

    Java中枚举类型的使用.docx

    在以上示例中,`MyEnum`是一个枚举类型的名字,而`CONSTANT1`、`CONSTANT2`和`CONSTANT3`则是这个枚举类型的具体常量。每个常量都是该枚举类型的一个实例。 #### 三、枚举类型的基本使用 1. **定义枚举类型:** ...

    全面掌握java枚举类型(enum-type)1

    全面掌握 Java 枚举类型(enum type) Java 枚举类型是一种特殊的数据类型,它可以取有限个数的明确值。枚举类型的引入解决了 int 枚举模式和 String 枚举模式的缺点,提供了类型安全性、可读性和性能等优势。 ...

    值类型与引用类型(.html)

    值类型包括基本类型(如int、double、bool等)、结构类型(如DateTime、Point等)以及枚举类型(enum)。值类型变量直接存储其值,这意味着当你对一个值类型变量进行赋值操作时,实际上是复制了该变量的值。这种复制...

    简单总结java枚举类型

    枚举常量之间可以使用`==`进行比较,因为它们是引用类型的等价比较,而非值的比较。 9. 枚举和序列化: 默认情况下,枚举是可序列化的。如果不想枚举实例被序列化,可以在枚举类型上添加`@java.io.Serializable`...

    枚举类型与构造函数.doc

    枚举类型与构造函数 枚举类型是一种特殊的数据类型,它可以在程序中定义一组固定的常量,...枚举类型和构造函数是Java中两种重要的概念,枚举类型可以定义一组固定的常量,而构造函数可以用于初始化对象的实例变量。

Global site tag (gtag.js) - Google Analytics