结构、枚举、装箱、拆箱
自定义值类型
如何利用结构来定义新的值类型,并使之具有与大多数预定义 类型相似的行为,这里的关键在于,任何
新定义的值类型都有它们自己的数据和方法。
一般用枚举来定义常量值集合。
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. VM Depot 镜像新增系列III – 社交媒体,内容管理 与 项目协同系统

     发布于 2014-06-30 作者 刘 天栋 对于架设可协同作业的网站平台, Windows  Azure有着得天独厚的优势.这不仅在于其强大的扩展性和安全性,更重要的是 Azure 平台对各类 ...

  2. Linux学习笔记15——GDB 命令详细解释【转】

    GDB 命令详细解释 Linux中包含有一个很有用的调试工具--gdb(GNU Debuger),它可以用来调试C和C++程序,功能不亚于Windows下的许多图形界面的调试工具. 和所有常用的调试工 ...

  3. 《JavaScript核心概念》基础部分重点摘录

    注:<JavaScript核心概念>适合深入了解JavaScript,比我买的<JavaScript框架设计>语言和内容丰富多了(可能是我水平尚浅吧). 1. 作用域 var ...

  4. JavaScript高级程序设计6.pdf

    ECMAScript通过RegExp类型来支持正则表达式 var expression=/pattern/flags;其中模式(pattern)部分是正则表达式,可以包含字符类.限定符.分组.向前查找 ...

  5. Windbg扩展的一些参考文章

    Windbg脚本和扩展工具开篇http://www.cnblogs.com/pugang/archive/2012/11/30/2796617.html WinDbg简单扩展DLL http://ww ...

  6. asp json

    <script language="JScript" runat="Server">function toObject(json) {    eva ...

  7. SRM 388(1-250pt)

    题意:定义一个数为k-smooth,如果它最大的质因子不超过k.给定n和k,求不超过n的,k-smooth的数有多少个.(k <= 100, n <= 10^5) 解法:对于一个数t,判断 ...

  8. JavaScript函数柯里化的一些思考

    1. 高阶函数的坑 在学习柯里化之前,我们首先来看下面一段代码: var f1 = function(x){ return f(x); }; f1(x); 很多同学都能看出来,这些写是非常傻的,因为函 ...

  9. Java内部类的一些总结

    作为刚入门Java的小白,这两天看到内部类,这里做一个总结,若有错误,欢迎指正~ 内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. 内部类分为: 成员内部类.局部内部类.静态嵌套类. ...

  10. Nearly prime numbers - SGU 113(素数)

    题目大意:判断一个数是否是两个素数的乘积,如果是,输出Yes,否则No. 分析:先打表求出来一部分素因子,用素数对素数判定还是比较快的. 代码如下: ========================= ...