C#学习笔记6

Posted 殇曲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#学习笔记6相关的知识,希望对你有一定的参考价值。

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#本质论 第三版》进行整理

以上是关于C#学习笔记6的主要内容,如果未能解决你的问题,请参考以下文章

《C#高级编程》学习笔记

c# 6.0 学习笔记

学习笔记:python3,代码片段(2017)

StyleCop学习笔记——初识StyleCop

C#学习笔记6

学习笔记:研读《C#入门经典》之易忽略的知识点