所有值类型继承自System.ValueType的疑惑

转自:https://www.cnblogs.com/jhxk/articles/2657489.html

 

比如说int吧,是值类型,是个struct,是这样声明的

public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int>

哪能看出来继承自ValueType?? 再说struct不是不能继承吗?为什么说继承自ValueType??不解。。。。

 

回答:

ValueType的确是类类型,但是他的子类却是值类型,这是因为CLR对他的子类经过了特殊的处理.CLR若判断某类继承自ValueType,那么会在内存分配方面使它具有值类型的特征(例如直接分配在栈上),这和类库的继承层次结构并无多大关系。
C#这边的编译器也经过了特殊处理,使值类型在诸多方面不同于类类型,例如,我们不可以声明一个继承自ValueType的值类型等等.

 

简单的说微软对.net中的值类型做了特殊处理使其继承自ValueType.注:语法上struct是不允许继承的,但可以实现接口.觉得微软挺恶心的.老搞一些和语法不符的东西.

 

很多类型都没有显示的继承基类,.net默认为继承object,以string为例,只直接继承object的.
struct是直接继承valuetype的,默认的,但struct有个特点,不能显示继承基类,即只能继承valuetype,所以就这样了.所以就像楼主看的一样了
书上说不能继承基类了,是因为C#是单继承了,已经有这valuetype了,所以不能继承了

 

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

 

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

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

  1. // Code #01  
  2. public enum Alignment  
  3. {  
  4.     Left,  
  5.     Center,  
  6.     Right  
  7. }  

--------------------------------------------------------------------------------
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代码如下:

  1. // Code #02  
  2. .class public auto ansi sealed Aligment  
  3.        extends [mscorlib]System.Enum  
  4. {  
  5.     .field public static literal Aligment Left = int32(0x00000000)  
  6.     .field public static literal Aligment Center = int32(0x00000001)  
  7.     .field public static literal Aligment Right = int32(0x00000002)  
  8.  
  9.     .field public specialname rtspecialname int32 value__  
  10. }  

从声明中,你可以看到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的声明:

  1. 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),但本身却是一个引用类型。
好吧,现在来看看下面代码,你能猜得出它的输出结果吗?

  1. // Code #04  
  2. static void Main()  
  3. {  
  4.     Type t = typeof(System.Enum);  
  5.  
  6.     if (t.IsEnum)  
  7.         Console.WriteLine("I'm enum type.");  
  8.  
  9.     if (t.IsValueType)  
  10.         Console.WriteLine("I'm value type.");  
  11. }  

请别惊讶于程序的运行结果没有任何输出!对于第一个判断,我们很清楚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#代码:

  1. // Code #05  
  2. // See Code #01 for Alignment.  
  3. static void Main()  
  4. {  
  5.     Alignment a = Alignment.Center;  
  6.  
  7.     Console.WriteLine(a.ToString());  
  8.  
  9.     Console.WriteLine(a);  
  10. }  

对应的IL代码是:

  1. // Code #06  
  2. .method private hidebysig static void Main() cil managed  
  3. {  
  4.     .entrypoint  
  5.     // Code Size: 32 byte(s)  
  6.     .maxstack 1  
  7.     .locals (  
  8.           EnumerationFaq.Alignment alignment1)  
  9.     L_0000: ldc.i4.1   
  10.     L_0001: stloc.0   
  11.     L_0002: ldloc.0   
  12.     L_0003: box EnumerationFaq.Alignment  
  13.     L_0008: call instance string [mscorlib]System.Enum::ToString()  
  14.     L_000d: call void [mscorlib]System.Console::WriteLine(string)  
  15.     L_0012: nop   
  16.     L_0013: ldloc.0   
  17.     L_0014: box EnumerationFaq.Alignment  
  18.     L_0019: call void [mscorlib]System.Console::WriteLine(object)  
  19.     L_001e: nop   
  20.     L_001f: ret   
  21. }  

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

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

  1. // Code #07  
  2. // See Code #01 for Alignment.  
  3. class Program  
  4. {  
  5.     static void Main()  
  6.     {  
  7.         Alignment a = Alignment.Center;  
  8.  
  9.         Print(a);  
  10.     }  
  11.  
  12.     static void Print(IConvertible c)  
  13.     {  
  14.         Console.WriteLine(c);  
  15.     }  
  16.  
  17.     static void Print(IFormattable f)  
  18.     {  
  19.         Console.WriteLine(f);  
  20.     }  
  21.  
  22.     static void Print(IComparable c)  
  23.     {  
  24.         Console.WriteLine(c);  
  25.     }  
  26.  
  27.     static void Print(Object o)  
  28.     {  
  29.         Console.WriteLine(o);  
  30.     }  
  31.  
  32.     static void Print(ValueType v)  
  33.     {  
  34.         Console.WriteLine(v);  
  35.     }  
  36.  
  37.     static void Print(Enum e)  
  38.     {  
  39.         Console.WriteLine(e);  
  40.     }  
  41. }  

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

  1. // Code #08  
  2. .method private hidebysig static void Main(string[] args) cil managed  
  3. {  
  4.     .entrypoint  
  5.     // Code Size: 15 byte(s)  
  6.     .maxstack 1  
  7.     .locals (  
  8.           EnumerationFaq.Alignment alignment1)  
  9.     L_0000: ldc.i4.1   
  10.     L_0001: stloc.0   
  11.     L_0002: ldloc.0   
  12.     L_0003: box EnumerationFaq.Alignment  
  13.     // 调用static void Print(Enum e);  
  14.     L_0008: call void EnumerationFaq.Program::Print([mscorlib]System.Enum)  
  15.     L_000d: nop   
  16.     L_000e: ret   
  17. }  
posted @ 2021-11-07 00:10  黑魔术师与黑魔术少女  阅读(169)  评论(0)    收藏  举报
1 3 levels of contents