结构体与类

1.什么是结构

  结构是程序员定义的数据类型,类似于类。它们都有数据成员和函数成员。

  区别就是:类是引用类型,结构是值类型

  结构是隐式封闭,不能被派生。 1 struct StructName 2 { 3 4 } 

2.结构是值类型

  结构类型的变量不能为null

  两个结构变量不能引用同以对象

3.对结构赋值

  对类赋值后CS2和CS1指向同一对象

  对结构赋值后,SS2和SS1成员的值相同

4.结构函数和析构函数

  结构可以有实例构造函数和静态构造函数,但不允许有析构函数

  语言隐式的为每个结构提供一个无参数的构造函数:

    ①把每个成员设置为该类型的默认值。(值成员被设置成他们的默认值,引用成员被设置成null)

    ②预定义的无参数构造函数对每个结构都存在,而且不能删除或重定义。

    ③可以创建另外的构造函数,只要有参数。【区别:类】对于类编译器只在没有其他构造函数声明提供隐式无参数构造函数

    ④调用构造函数,需使用new运算符。即使不从堆中分配内存也使用new

    ⑤也可以不使用new运算符创建结构的实例,但是会有限制:不能使用数据成员的值,直到显式的设置它;不能调用任何函数成员,直到所有数据成员已经被赋值。

5.静态构造函数

  【相似:类】结构的静态构造函数创建并初始化静态数据成员,而且不能引用实例成员。结构的静态函数构造遵从与类的静态构造函数一样的规则。

  静态构造函数在下面两个行为的第一个之前被调用

  ①调用显式声明的构造函数

  ②对结构静态成员的引用

6.构造函数和析构函数的总结

类型  描述
实例构造函数(无参数) 不能在程序中声明。系统为所有结构提供一个隐式的构造函数,它不能被程序删除或重定义
实例构造函数(有参数)  可以在程序中声明。
静态构造函数 可以在程序中声明。
析构函数 不能在程序中声明。析构函数不被允许

7.字段初始化是不被允许的

  在结构中字段初始化是不允许的。

8.结构是密封的

  结构总是隐式密封的,因此,不能从它们派生其他结构。

  由于结构不支持继承,个别类成员修饰符用在结构成员上将没有意义。因而,他们不能被用在结构成员声明中。不能用于结构的修饰符如下:

  protected

  internal

  abstract

  virtual

  结构本省派生自System.ValueType,System.ValueType派生object

  两个可以用于结构成员继承相关的关键字是new和override修饰符,当创建一个和基类System.ValueType的成员有相同名称的成员时使用它们。所有结构都派生自System.ValueType.

9.装箱和取消装箱

  如同其他值类型数据,如果想使用一个结构实例作为引用类型,必须执行装箱的复制。装箱和装箱取消在后面的文章中会详述。

10.结构可以作为返回值和参数

  返回值:当结构作为返回值时,一个复制被创建并从函数成员返回

  值参:当结构被用作值参时,一个实际参数的复制被创建。该复制被用在方法的执行中

  ref和out参数:如果把结构用作ref或out参数,一个对该结构的引用被传入方法,这样其数据成员就能被改变。

11.关于结构的附加信息

  分配结构比创建类的实例需要更少的消耗,所以使用结构代替类有时可以提高性能,但要注意到装箱和取消装箱的高代价。

  预定义简单类型(int、short、long等)尽管在.NET和C#中被视为原始类型,它们实际上在.NET中都被实现为结构。

  可以使用声明partial类相同的方法声明partial结构

  结构就像类,可以实现接口。接口将在后面的文章中详述。

12.[StructLayout(LayoutKind.Sequential)]在机构体前的声明

  首先[]表示标记语言标记绝大部分的作用是告诉IDE或者编译器 这个类 结构体 或者这个属性(不止是类可以加标记哦)有一些什么特别之处。

  结构体是由若干成员组成的.布局有两种
    1.Sequential,顺序布局,比如
  struct S1
  {
    int a;
    int b;
  }
  那么默认情况下在内存里是先排a,再排b
  也就是如果能取到a的地址,和b的地址,则相差一个int类型的长度,4字节
  [StructLayout(LayoutKind.Sequential)] 
  struct S1
  {
    int a;
    int b;
  }
  这样和上一个是一样的.因为默认的内存排列就是Sequential,也就是按成员的先后顺序排列.
  2.Explicit,精确布局
  需要用FieldOffset()设置每个成员的位置
  这样就可以实现类似c的公用体的功能
  [StructLayout(LayoutKind.Explicit)] 
  struct S1
  {
    [FieldOffset(0)]
    int a;
    [FieldOffset(0)]
    int b;
  }
  这样a和b在内存中地址相同