c#之结构体
结构和类的区别:
1、结构是值类型,它在栈中分配空间;而类是引用类型,它在堆中分配空间,栈中保存的只是引用。
2、结构类型直接存储成员数据,让其他类的数据位于堆中,位于栈中的变量保存的是指向堆中数据对象的引用。
C#中的简单类型,如int、double、bool等都是结构类型。如果需要的话,甚至可以使用结构类型结合运算符运算重载,再为C#语言创建出一种新的值类型来。
由于结构是值类型,并且直接存储数据,因此在一个对象的主要成员为数据且数据量不大的情况下,使用结构会带来更好的性能。
一、声明结构的语法 - struct关键字
public struct AddressBook
{
//字段、属性、方法、事件
}
对于类而言,两个变量指向同一个对象的情况是存在的,因此对这样两个变量中的任意一个进行操作,起结果必然会影响另外一个,因为它们指向的是同一个对象。
结构是值类型,,直接包含它自己的数据,每个结构都保存自己的一份数据,修改每一个结构的数据都不会对其他结构的数据造成影响。
二、给结构赋值
如果从结构中创建一个对象,并将该对象赋给某个变量,则该变量包含结构的全部值。复制类型为结构的变量时,将同时复制该结构所持有的所有数据。由于结构不是引用类型,因此结构类型的变量不能被赋予null值。
public class Program
{
static void Main(string[] args)
{
PersonStruct p1, p2; //与类一样,但可以不new
p1.Name = "张飞";
p1.MobilePhone = "13553663108";
p1.Birthday = DateTime.Now.AddYears(-10); p2 = p1; //将p1的值赋给p2 //由于是值类型,因此赋值等于将全部值全部复制到p2的栈空间
p2.Name = "关羽"; //然后修改p2的值看是否会影响p1
Console.WriteLine(p1.Name); //输出 张飞 没影响 PersonClass p3 = new PersonClass();
p3.Name = "张飞";
p3.MobilePhone = "13553663108";
p3.Birthday = DateTime.Now.AddYears(-10); PersonClass p4 = new PersonClass();
p4 = p3; //将p3的值赋给p4 赋值后,由于是引用类型,因此两个对象指向的是同一个地址(堆空间)
p4.Name = "关羽"; //然后修改p4的值看是否会影响p3
Console.WriteLine(p3.Name); //输出 关羽 没影响 Console.ReadKey();
}
} public class PersonClass
{
public string Name;
public string MobilePhone;
public DateTime Birthday;
} public struct PersonStruct
{
public string Name;
public string MobilePhone;
public DateTime Birthday;
}
将一个结构变量赋值给另一个结构变量,就是把数据从一个结构复制到另一个结构。而类则不同,在类的变量之间,复制的是引用,而不是类数据。。因此当数据比较大的时候,这种数据复制机制会带来较大的开销。
三、构造函数
结构类型可以有实例构造函数和静态构造函数,但不能有析构函数。
1、实例构造函数
结构类型都有一个预定义的,没有参数的构造函数,这点与类是一样的。此构造函数不允许删除和重定义,并且这个无参数的构造函数会一直存在,并不会因为定义了其他带参数的构造函数就消失,这一点和类不同。
注意如果没有使用new运算符,是不可以使用数据成员的值(除非已显示地设置了该数据成员的值)和调用函数成员的(除非所有数据成员均已经被赋值)。
四、静态构造函数
和类一样,结构类型也可以有静态构造函数,静态构造函数用于初始化静态数据成员。静态构造函数有如下特点:
1、静态构造函数不能有访问修饰符和参数;
2、静态构造函数不能访问实例成员;
3、静态构造函数无法直接进行调用;
结构和类的静态构造函数的触发规则不同,类的静态构造函数是在创建第一个实例或引用任何静态成员之前自动调用的,而结构的静态构造函数在以下情况调用:
1、使用显式声明的构造函数进行初始化
2、调用结构的方法或访问结构的静态数据成员(无论是读取还是赋值,访问实例数据成员不会触发CLR自动调用静态的构造函数)。
五、结构的多态和可继承性
结构直接派生自System.ValueType,间接派生自System.Object,但结构是隐式密封的,不能作为基类在派生出其他的结构,也不能从类派生,但可以从接口派生。
结构的特性:
1、结构类型总是隐式密封的,因此在定义结构时不能使用sealed和abstract关键字;
2、因为结构不能作为基类,结构的成员不能使用如下访问修饰符:protected和protected,internal;
3、结构的函数成员不能声明为abstract和virtual,但是可以使用override关键字,用以覆写它的基类System.ValueType中的方法。
六、结构的装箱与拆箱
结构是值类型,因此当它被转换为object类型时,或者它所实现的接口类型的时候,就会执行装箱操作;同样,当执行相反操作的时候,就会执行拆箱操作。
七、结构和类的对比
结构 类
数据类型 值类型 引用类型
是否必须使用new运算符实例化 否 是
是否可声明无参数的构造函数 否 是
数据成员可否在声明的同时初始化 声明为const或static可以,数据成员不可以 可以
直接派生自什么类型 System.ValueType 有
是否有析构函数 无 有
可否从类派生 否 可以
可否实现接口 可以 可以
实例化时在栈还是在堆分配内存 栈 堆,栈中保存引用
该类型的变量可否被赋值为null 否 可以
可否定义私有的无参构造函数 否 可以
是否总有一个默认的无参构造函数 是 否
无论结构使用预定义的、无参数的构造函数,还是使用用户定义的、有参数的构造函数进行初始化,都会初始化结构的数据成员。不过预定义的,无参的会将数值型初始化为默认值,引用类型初始化为null;而用户自定义的初始化策略对个成员进行初始化。因此结构类型的数据成员不允许在声明是显式初始化。
八、性能
因为结构是值类型,因此在为结构分配内存,或者当结构超出了作用域被删除时,性能会非常好,因为他们将内联或者保存在堆栈中。当把一个结构类型的变量赋值给另一个结构时,对性能的影响取决于结构的大小,如果结构的数据成员非常多而且复杂,就会造成损失,接下来使用一段代码来说明这个问题。
结构和类的适用场合分析:
1、当堆栈的空间很有限,且有大量的逻辑对象时,创建类要比创建结构好一些;
2、对于点、矩形和颜色这样的轻量对象,假如要声明一个含有许多个颜色对象的数组,则CLR需要为每个对象分配内存,在这种情况下,使用结构的成本较低;
3、在表现抽象和多级别的对象层次时,类是最好的选择,因为结构不支持继承。
4、大多数情况下,目标类型只是含有一些数据,或者以数据为主。
c#之结构体的更多相关文章
- Go结构体实现类似成员函数机制
Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...
- C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱
一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...
- go语言结构体
定义: 是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体. 成员: 每个值称为结构体的成员. 示例: 用结构体的经典案例处理公司的员工信息,每个员工信息包含一个唯一的员工编号.员工的名字. ...
- C语言中的结构体
用户自己建立自己的结构体类型 1. 定义和使用结构体变量 (1).结构体的定义 C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体. (2).声明一个结构体类型的一般形式为: ...
- C++_系列自学课程_第_12_课_结构体
#include <iostream> #include <string> using namespace std; struct CDAccount { double bal ...
- java socket传送一个结构体给用C++编写的服务器解析的问题
另一端是Java写客户端程序,两者之间需要通信.c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组.解决方法:c++/c socket 在发送结构体的时候其实发送的也是字 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- HDOJ 1009. Fat Mouse' Trade 贪心 结构体排序
FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- C语言结构体对齐
1.结构体变量中的元素如何访问? (1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式):实质上都是指针方式访问.(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来 ...
- C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用
类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...
随机推荐
- 恶意软件伪装“正规军”,撕开Booster Cleaner“画皮”下的真相
经常使用手机浏览器阅读小说的用户都知道,在浏览器页面经常会出现一些推广游戏应用.手机清理应用等应用的弹窗广告.有时出于方便,我们也会选择直接点开这些弹窗广告进行应用下载.但这种行为并不安全,部分恶意应 ...
- 使用Nito.AsyncEx实现异步锁(转)
转载地址:http://www.cnblogs.com/1zhk/p/5269279.html Lock是常用的同步锁,但是我们无法在Lock的内部实现异步调用,比如我们无法使用await. 以下面的 ...
- TextView属性android:ellipsize="marquee"不生效的解决办法
最近自己在写自己的第一个app,过程中遇到了这个问题,查了不少帖子,经过尝试发现,这种问题一般分为两类: 1. TextView的Text值赋值后不更改,很多帖子上说如下写法就可以生效: <Te ...
- 解决MVC4 时间验证Bug
MVC验证时间控件(my97,时间格式:yyyy-MM-dd HH:mm:ss) 在谷歌浏览器上一切正常.但在火狐和IE 上一直验证不通过 (错误信息:日期格式不对) 猜想是 时间格式的问题..日期 ...
- Beginning Scala study note(1) Geting Started with Scala
1. Scala is a contraction of "scalable" and "language". It's a fusion of objecte ...
- JS应用,表单上的一些东西
例: <body> <form>我的生日是哪一年? <input type="text" value="" id="t1 ...
- silverlight使用小计(先做记录后续整理)
1.Grid: a.通过获取指定行的高度和指定列的宽度来获取指定单元格的宽高 b.几种宽高默认值: 宽高(Width/Heigth):1* 最大宽高(MaxWidth/MaxHeigth):正无穷大 ...
- JQuery.validate.js 表单验证
官方网站:http://bassistance.de/jquery-plugins/jquery-plugin-validation/API: http://jquery.bassistance.de ...
- Jsonp跨域
Jsonp.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- orm映射 封装baseDao
是用orm映射封装自己封装dao层 思路:通过映射获得实体类的属性拼接sql语句 import java.lang.reflect.Field; import java.lang.reflect.In ...