1.结构:结构除了可以含有属性和字段,还可以包方法和构造器,但不能包含黠认(无参数}的构造器。有的时候(比如在实例化一个数组的时候)不会调用值类型的构造器,因为所有数组内存都转为用零来初始化,为了避免因为默认构造器只是偶尔调用而造成不一致,C#完全禁止了用户显式定义默认构造器,因为编译器会将声明时的实例字段赋值放到类型的构造器中进行。在构造器中必须对 struct中的所有字段进行初始化,如果没有做到这一点,就会产生编译错误,可查看Angle结构的代码。
2.结构的继承与接口:所有值类型都是密封的,除此之外,所有值类型都派生自system.ValueType,这意味着struct的继承链息是从object到ValueType到struct。值类型还能实现接口,许多接口都是实现接口框架固定组成部分,比如 IComparilble 和IFormattable。
3.装箱与拆箱:装箱就是把值类型变成引用类型,如下:
(1) 首先在堆中分配好内存,它将用于存放值类型的数据以及少许额外开销;
(2) 接着发生一次内存复制动作,栈上的值类型数据复制到堆上分配好的位置;
(3) 最后,对象或接口引用得到更新,指向堆上的位置;
拆箱就是把引用类型变成值类型,如下:根据定义,CIL 指令 unbox 只是对堆上的数据进行解引用,并不包括从堆复制到栈的动作。但在 C#语言中,太多数时候紧接着在拆箱之后发生一次复制动作。装箱和拆箱之所以重要,是因为装箱去对性能和行为造成一些影响。开发者可以通过查看CIL,在一个特定的代码片段中统计 box/unbox 指令的数量。在BoxAndUnbox()中的代码就存在多次的装箱与拆箱,这样编写的代码是不合理。
4.枚举:枚举和其他值类型稍有不同,因为枚举的继承链是从System.ValueType到System.Enum,再到enum。
5.枚举与字符串的转换:枚举ToString()后会输出枚举标识符,使用Enum.Parse或Enum.TryParse方法可以把字符串转化为枚举,后一个方法是.Net4.0新增的泛型方法。此中我们也可以使用Enum.IsDefined()方法来检查一个值是否包含在一个枚举中。
6.枚举作为“位标志”使用:
(1)可以查看如下“FileAttributes“枚举的设定(即System.IO。FileAttributes的设定),作为位标志后,其值可以*组合,所以可以使用Or运算符来联结枚举值。如本示例中BitFlag()方法的使用。当然枚举中的每个值不一定只对应一个标志,完全可以为常用的标志组合定义额外的枚举值。
(2)使用位标志类型的时候,位标志枚举应该包含[FlagsAttribute]这个特性,这个标志指出多个枚举值可以组合使用,此外,它改变了ToString()和Parse()方法的行为。例如为一个已用FlagsAttribute修饰了的枚举调用ToString()方法,会为已设置的每个枚举标志输出对应的字符串(如BitFlag2()的示例),而如果没有这个修饰,,返回的就是组合后数值。
public struct Angle { public Angle(int hours, int minutes, int seconds) { Hours = hours; Minutes = minutes; Seconds = seconds; } public int Hours { get; set; } public int Minutes { get; set; } public int Seconds { get; set; } public Angle Move(int hours, int minutes, int seconds) { return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds); } } [Flags] public enum FileAttributes { ReadOnly = 1 << 0, Hidden = 1 << 1, System = 1 << 2, Directory = 1 << 3, Archive = 1 << 5, Device = 1 << 6, Normal = 1 << 7, Temporary = 1 << 8, SparseFile = 1 << 9, ReparsePoint = 1 << 10, Compressed = 1 << 11, Offline = 1 << 12, NotContentIndexed = 1 << 13, Encrypted = 1 << 14 } public void BitFlag() { string fileName = @"enumtest.txt"; FileInfo file = new FileInfo(fileName); file.Attributes = FileAttributes.Hidden | FileAttributes.ReadOnly; Console.WriteLine("{0} | {1} = {2}", FileAttributes.Hidden, FileAttributes.ReadOnly, (int)file.Attributes); if ((file.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) { throw new Exception("File is not hidden"); } if ((file.Attributes & FileAttributes.ReadOnly) != FileAttributes.ReadOnly) { throw new Exception("File is not read-only"); } //.... } public void BitFlag2() { string fileName = @"enumtest.txt"; FileInfo file = new FileInfo(fileName); file.Open(FileMode.Create).Close(); FileAttributes startingAttributes = file.Attributes; file.Attributes = FileAttributes.Hidden | FileAttributes.ReadOnly; Console.WriteLine("\"{0}\" output as \"{1}\"", file.Attributes.ToString().Replace(",", "|"), file.Attributes); FileAttributes attributes; Enum.TryParse(file.Attributes.ToString(), out attributes); Console.WriteLine(attributes); File.SetAttributes(fileName, startingAttributes); file.Delete(); } public void BoxAndUnbox() { int totalCount; ArrayList list = new ArrayList(); Console.Write("Enter a number between 2 to 1000:"); totalCount = int.Parse(Console.ReadLine()); list.Add((double)0); list.Add((double)1); for (int i = 2; i < totalCount; i++) { list.Add((double)list[i - 1] + (double)list[i - 2]); } foreach (double num in list) { Console.Write("{0},", num); } }
----------------------以上内容根据《C#本质论 第三版》进行整理