结构、枚举、装箱、拆箱
自定义值类型
如何利用结构来定义新的值类型,并使之具有与大多数预定义 类型相似的行为,这里的关键在于,任何
新定义的值类型都有它们自己的数据和方法。
一般用枚举来定义常量值集合。
1、值类型
所有值类型都派生自类System.ValueType。而所有类都派生自类System.Object。
值类型直接包含值。换言之,变量引用的位置就是值在内存中实际存储的位置。因此,
将第一个变量的值赋值给第二个变量,会在新变量的位置创建原始变量的值的一个内存副本。
所以改变第一个变量的值不会影响第二个变量的值,因为值类型会使用内存中的特定位置。
值类型需要的内存量会在编译时固定下来,不会在运行时改变。因为大小是固定的,所有值类型可以存储在称为
栈的内存区域中。
2、引用类型
引用类型也是一个变量,如上所述变量引用的位置就是值在内存中实际存储的位置,存储在栈中(但存储的数据是一个内存地址,大小是一个整形数据所占的字节数,而不是我们存储的实际数据),存储在这个变量中的内存地址号所指的内存,才是真正我们存储的实际数据)
,实际数据在堆中。这个内存地址号指向的是堆中的内存块。
 
运行时,从变量中读取内存位置,然后根据内存地址所指去堆中查找包含实际数据的内存。
 
所以在赋值给另一个变量时,复制的是一个内存地址号(是实际数据存储的内存地址,而不是实际数据,经过了一个间接跳转)。
 
在运行时,改变这个变量的数据而不是它的指向时(所谓改变指向就是重新指向一个新的地址),会改变实际数据。
 
当作为函数参数时,如果被声明为ref或out时,值类型和引用类型复制的统一是该变量的内存号,
所以如果是值类型,可以改变这个内存号中()的数据。也就实际数据(实参的数据)。
如果是引用类型,除了像以上可以改变实际数据以外,还可以改变传进来实参的指向,而且会取消对原来实际数据的指向(如果实际数据的指向只有此一个,这段内存将会在下一次垃圾回收时进行内存回收)。
 
 
 
注:内存号实际是一个整型数据(用来可以表示所有内存地址号的整型)32位,或者64位,一由处理器的位数决定。
 
1、结构(值类型)
注:虽然语言本身没有作要求,但作为一个良好的习惯,应该确保值类型是不可变的,换言之,一旦实例化好了一个值类型
,那个实例不能修改。如果需要修改,应该创建一个新的实例。
 
除了属性和字段,struct中还可以包含方法和构造器,但不能包含默认(无参数)的构造器。有的时候(比如在实例化一个数组的时候)
不会调用值类型的构造器,因为所有数组内存都转为用零来初始化。为了避免因为默认构造器只是偶尔调用而造成不一致,
C#完全禁止了用户显式定义默认构造器因为编译器会将声明时的实例字段赋值放到类型的构造器中进行,所以 C#相当于禁止了在声明时对实例字段进行赋值。
C#支持带参数的构造器。且需要在构造器中对所有字段进行初始化,否则会产生编译错误。
因为是值类型,所以没有终结器。垃圾回收只针对在堆中分配的内存。
 
default运算符的使用
default(数据类型)
如:default(int)
 
值类型都是密封的,所有值类型都派生自System.ValueType。这意味着struct的继承链问题从object到ValueType到struct。
 
值类型还能实现接口。
和类一样,可以在值类型中重写System.Object的virtual成员。
与引用类型重写的一个区别在于,对于值类型来说,GetHashCode()的默认实现昌将调用转发给struct的第一个非空字段。
此外,Equals()大量利用了反射机制。所以,假如一个值类型在集合中频繁使用,尤其是使用了码的字典类型的集合,那么值
类型应该同时包含对Equals()和GetHashCode()的重写。

     struct Angle
{ public Angle(int hours, int minutes, int seconds)
{
_Hours = hours;
_Minutes = minutes;
_Seconds = seconds;
}
public int Hours
{
get
{
return _Hours;
}
}
private int _Hours;
public int Minutes
{
get
{
return _Minutes;
}
}
private int _Minutes;
public int Seconds
{
get
{
return _Seconds;
}
}
private int _Seconds;
public Angle Move(int hours, int minutes, int seconds)
{
return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
}
} class Coordinate
{
public Angle Latitude
{
get
{
return _Longitude;
}
set
{
_Longitude = value;
}
}
private Angle _Longitude; public Angle Latitude
{
get
{
return _Latitude;
}
set
{
_Latitude = value;
}
}
private Angle _Latitude;
}
2、装箱
由于局部变量值类型(函数当中声明的变量)直接包含了它们的数据,而它们的接口和System.Object包含的是对它们的数据的引用。
因此必须认真考虑当一个值类型转成它实现的某个接口或者它的根基类object的时候,会发生什么。
这样的转型过程称为装箱。
从一个值类型转换成一个引用类型时,会涉及以下几个步骤。
步骤一:首先在堆中分配好内存,它将用于存放值类型的数据以及少许额外开销(一个SyncBlockIndex以及方法表指针)
步骤二:接着发生一次内存复制动作,栈上的值类型数据得到到堆上分配好的位置。
步骤三:最后,对象或接口引用得到更新,指向堆上的位置。
 
相反的过程称为拆箱。根据定义,CIL指令unbox只是对堆上的数据进行解引用(取消引用),并不包括从堆复制到栈的动作。
但在C#语言中,大多数时候都会紧接在拆箱之后发生一次复制动作。
 
装箱和拆箱会对性能和行为造成一些影响 。(应该多看CIL,在一个特定的代码片断中统计box/unbox指令的数量)
 
需要额外学习:待学习。 如何避免装箱和拆箱
 
 
3、枚举
枚举是开发者可以定义的一个类型。枚举的关键特征在于它标识了一个在编译时定义的所有可能值的集合,每个值都由一个名称来引用。
要引用一个枚举值,需要为其附加枚举名称前缀。
     enum ConnectionState : short
{
Disconnected,
Connecting = ,
Conntected,
Joined = Conntected,
Disconnecting
}
第一个枚举值默认为0,以后自动加1 
枚举问题具有一个基础类型,这可能是int、uint、logn、ulong。但不能是char
默认值类型是Int.但可以使用继承语法来指定一个不同的类型。
枚举类型的性能完全取决于基础类型的性能。
 
注:在没有对应的枚举值的前提下也允许转型 ,优点在于枚举能在未来的API发布中添加新值,而且不会破坏早期的版本。
 
枚举和其他值类型稍有不同,因为枚举的继承链是从System.ValueType到System.Enum,再到enum。
 
3、1枚举之间的类型兼容性
C#不支持两个不同的枚举数组之间的直接转型,但是可以通过中间数据类型(数组)进行转换。
 
3、2 枚举和字符串之间的转换
输出枚举标识符。
 
3、3 枚举作为标志使用
可以使用移位来赋值。
 
或者 or 或者 and  
 
或者 使用 FlagsAttribute:   [Flags]放在枚举之前,这个标志指出多个枚举值组合使用。
 
 
枚举和结构仍需要强化学习。
 
 
 
 
 
 
 

八、C# 值类型的更多相关文章

  1. [你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理

    原文地址:http://kb.cnblogs.com/page/42318/ 系列文章导航: [你必须知道的.NET] 开篇有益 [你必须知道的.NET] 第一回:恩怨情仇:is和as [你必须知道的 ...

  2. Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义

    一.Java中什么叫做引用类型变量?引用:就是按内存地址查询       比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...

  3. JAVA初学(1):值类型和引用类型的区别

    JAVA值类型和引用类型的区别(转)                                                          [定义] 引用类型表示你操作的数据是同一个,也就 ...

  4. java中值类型和引用类型的区别

    [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变. 值类型表示复制一个当前变量传给方法,当你 ...

  5. 学习记录 java 值类型和引用类型的知识

    1. Java中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值, 那么调用这个方法是传入的变量的值也将改变 ...

  6. JAVA中值类型和引用类型的不同(面试常考)

    转载:https://www.cnblogs.com/1ming/p/5227944.html 1. JAVA中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个 ...

  7. 3、二、c# 面向对像编程。类,结构、C# 数据类型(引用类型、值 类型、指针类型)、ref参数与out参数、方法的重载、静态类型与静态成员、继承与多态、委托与事件

    一.类 定义类使用class关键字. <access specifier> class class_name { // member variables 成员变量 <access s ...

  8. C# 构造基础返回值类型-BaseResponse

    学无止境,精益求精 十年河东,十年河西,莫欺少年穷 用于基础返回值类型,如下: using System; using System.Collections.Generic; using System ...

  9. 三.protobuf3标量值类型

    Protobuf3 标量值类型 标量消息字段可以具有以下类型之一——该表显示了.proto文件中指定的类型,以及自动生成的类中的相应类型: .proto类型 说明 C++ 类型 Java 类型 Pyt ...

随机推荐

  1. SQL*Net message to client

    SQL*Net message to client The server (foreground process) is sending a message to the client. 这个wait ...

  2. SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)

    题意: 求树上A,B两点路径上第K小的数 分析: 同样是可持久化线段树,只是这一次我们用它来维护树上的信息. 我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表 ...

  3. std::min 与std::max 的 Compiler Error C2780

    代码 #include<iostream>#include <algorithm> // std::min#undef minint main(){ float a =15.0 ...

  4. 2013.08.23.diary

    Today, my baby called me.She said, she want to go abroad . And she wants me to go abroad too. I thin ...

  5. (转载)ASP网站如何防止注入漏洞攻击

    SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如 果管理员没查看IIS日志的习惯,可能被入侵很长时间都不会发觉.但 ...

  6. 《Linear Algebra and Its Applications》-chaper3-行列式-克拉默法则

    计算线性方程组唯一解的克拉默法则:

  7. HDU-1300(基础方程DP-遍历之前所有状态)

    Problem Description In Pearlania everybody is fond of pearls. One company, called The Royal Pearl, p ...

  8. hdu 1081 矩阵最大连续子序列

    问题描述:二位平面图,每一个坐标都有值,正值或负值,求任意矩形中和的最大值问题 解决方案:求解图中每一个坐标为起点,求任意长度宽度的矩形的和 #include<iostream> #inc ...

  9. OPC客户端的进程安全初始化

    现场OPC客户端无法获取远程OPC Server列表,也无法连接OPC Server,经查调用CoCreateInstanceEx()创建IID_IOPCServerList接口正常,但调用IOPCS ...

  10. 并查集hdu1232

    Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道 ...