结构

什么是结构


结构是程序员定义的数据类型,与类非常相似。它们有数据成员和函数成员。结构与类的重要区别是:

  • 类是引用类型而结构是值类型
  • 结构是隐式密封的,这意味着它们不能被派生

声明结构的语法与声明类相似

关键字

struct SturctName
{
MemberDeclarations
}

例:Point结构

struct Point
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
Point first,second,third;
first.X=;first.Y=;
second.X=;second.Y=;
third.X=first.X+second.X;
third.Y=first.Y+second.Y;
Console.WriteLine("first: {0},{1}",first.X,first.Y);
Console.WriteLine("second: {0},{1}",second.X,second.Y);
Console.WriteLine("third: {0},{1}",third.X,third.Y);
}
}

结构是值类型


和所有值类型一样,结构类型变量含有自己的数据。因此:

  • 结构类型变量不能为null
  • 两个结构变量不能引用同一对象

例:结构变量的内存安排

class CSimple
{
public int X;
public int Y;
}
struct Simple
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
var cs=new CSimple();
var ss=new Simple();
...
}
}

对结构赋值


把一个结构赋值给另一个结构,就将一个结构的值复制给另一个结构。这和复制类变量不同,复制类变量时只复制引用。
例:结构变量赋值与类变量赋值的区别

class CSimple
{
public int X;
public int Y;
}
struct Simple
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
CSimple cs1=new CSimple(),cs2=null;
Simple ss1=new Simple(),ss2=new Simple();
cs1.X=ss1.X=;
cs1.Y=ss1.Y=;
cs2=cs1;
ss2=ss1;
}
}

构造函数和析构函数


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

实例构造函数

语言隐式地为每个结构提供一个无参构造函数。这个构造函数把结构的每个成员设置为该类型的默认值。值成员设置成它们的默认值,引用成员设置为null。
例:带参数的构造函数

struct Simple
{
public int X;
public int Y;
public Simple(int a,int b)
{
X=a;
Y=b;
}
}
class Program
{
static void Main()
{
var s1=new Simple();
var s2=new Simple(,);
Console.WriteLine("{0},{1}",s1.X,s1.Y);
Console.WriteLine("{0},{1}",s2.X,s2.Y);
}
}

也可以不是用new运算符创建结构实例,然而这样做,有一些限制:

  • 在显式设置数据成员后,才能使用它们的值
  • 在对所有数据成员赋值后,才能调用任何函数成员

例:不用new创建结构实例

struct Simple
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
Simple s1,s2;
Console.WriteLine("{0},{1}",s1.X,s1.Y); //编译错误
↑ ↑
还未赋值
s2.X=;
s2.Y=;
Console.WriteLine("{0},{1}",s2.X,s2.Y); //没错误
}
}
静态构造函数

与类相似,结构的静态构造函数创建并初始化静态数据成员,而且不能引用实例成员。
以下两种行为发生前,会调用静态构造函数

  • 调用显式声明的构造函数
  • 引用结构的静态成员
构造函数和析构函数小结

字段初始化语句是不允许的


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

struct Simple
{
public int x=; //编译错误
public int y=; //编译错误
}

结构是密封的


结构总是隐式密封的,因此,不能从它们派生其他结构。
结构不支持继承,所以下列修饰符不能用于结构声明:

  • protected
  • internal
  • abstract
  • virtual

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

装箱和拆箱


如同其他值类型数据,如果想将一个结构实例作为引用类型对象,必须创建装箱(boxing)副本。装箱的过程就是制作值类型变量的引用类型副本。装箱和拆箱(unboxing)在第16章详述。
6个重要的.NET概念: - 堆栈,堆,值类型,引用类型,装箱和拆箱

结构作为返回值和参数


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

  • 返回值 当结构作为返回值时,将创建它的副本并从函数成员返回
  • 值参数 当结构作为值参数时,将创建实参结构的副本。该副本用于方法的执行中
  • ref和out参数 若把一个结构用作ref或out参数,传入方法的是结构的引用,这样就可以修改其数据成员

关于结构的其他信息


对于结构进行分配比创建类的实例开销小,所以使用结构替代类有时可以提高性能,但要注意到装箱和拆箱的高代价。
关于结构,需要知道的最后一些事情如下:

  • 预定义简单类型(int、short、long等等),尽管在.NET和C#中被视为原始类型,它们实际上在.NET中都实现为结构
  • 可以使用与声明分部类相同的方法声明分部结构,如第6章所述。

结构和类一样,可以实现接口。接口将在第15章阐述。

最新文章

  1. shell 里的变量 总结
  2. Centos6.X下安装php nginx mysql 环境
  3. Asp.net MVC 利用自定义RouteHandler来防止图片盗链
  4. jQuery之换肤与cookie插件
  5. CALayer 图层
  6. 基于jQuery查找dom的多种方式性能问题
  7. Python之旅.第四章.模块与包.总结(未完待遇)
  8. Hibernate异常之关键字错误
  9. Android状态栏着色
  10. ubuntu在终端下复制粘贴的2种方法
  11. js取得background属性url的值--移动端【踩坑】
  12. PHP MYSQL 临时表的使用
  13. IAR8.11.1安装与破解教程
  14. 关于sdk>=23的android版本权限的问题
  15. 深入聊聊Java多线程
  16. OpenAI Gym
  17. [svc]ext4文件删除&访问原理
  18. 【转载】TCP慢启动、拥塞避免、快速重传、快速回复
  19. 关于Java Logger类的使用问题 - 内存不释放
  20. win7在64位系统下编译openssl

热门文章

  1. BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]
  2. ElasticSearch安装中遇到的一些问题
  3. 算法&数据结构系列 -- 堆(优先队列)
  4. [解决问题] E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
  5. redux middleware 源码分析
  6. [翻译] .NET Core 2.1 Preview 1 发布
  7. TP5整合 WorkerMan 以及 GatewayWorker
  8. Office 365 共享链接直接进入编辑
  9. 聊聊JavaScript-闭包
  10. AGC010 - A: Addition