结构体与类
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在内存中地址相同