对值类型和引用类型理解,是理解C#语言基础的重要主题之一。这里会介绍一下内容:
值类型:值类型实例要么分配在堆栈上,要么分配在堆上(此时以类型的字段存在托管堆上)。值类型包括简单类型、结构体类型和枚举类型等。定义值类型用关键字Struct。(由于值类型均是密封的,意味着所有定义的值类型均继承字ValueType,且不能派生,但是可以实现接口),如果值类型实例分配在堆栈上,那么方法调用退出后则销毁;若位于GC堆上,则随其所在对象消亡而消亡,主要有GC控制。由于值类型本身包含值,通常分配在堆栈上,访问无需地址转换,分配空间自动释放,所以值类型的效率更高。
引用类型:引用类型实例分配在托管堆上,而引用类型变量仅仅是持有对象在托管堆上的引用,等于是建立了实例和变量之间的关系。定义引用类型通常用关键字calss,interface,delegate.引用类型实例由GC控制回收。
如下:在Main方法中定义了值类型变量a,引用类型变量stu
class Program { static void Main(string[] args) { Pointer a; a.X = 100; a.Y = 200; Console.WriteLine("鼠标当前位置为{0},{1}",a.X,a.Y); Student stu=new Student("Josh","Smith",100,Sex.Shemale); stu.Learn(); } } /// <summary> /// 定义一个代表鼠标位置的pointer类 /// </summary> public struct Pointer { /// <summary> /// 水平位置 /// </summary> public int X ; /// <summary> /// 垂直位置 /// </summary> public int Y ; } /// <summary> /// 学生 /// </summary> public class Student { //名称 private string _lastName; //姓 private string _firtName; //名子 public string Name { get { return _firtName+ _lastName; } } private Sex _sex=Sex.UnKnow; /// <summary> /// 性别 /// </summary> public Sex Sex { get { return _sex; } } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 学习 /// </summary> public void Learn() { Console.WriteLine("{0}学生学习",Name); } /// <summary> /// 构造函数 /// </summary> /// <param name="argFirstName">姓</param> /// <param name="argLastName">名称</param> /// <param name="argAge">年龄</param> /// <param name="argSex">性别</param> public Student(string argFirstName, string argLastName, int argAge, Sex argSex) { _firtName= argFirstName; _lastName= argLastName; _sex = argSex; Age = argAge; } } /// <summary> /// 人的性别 /// </summary> public enum Sex { /// <summary> /// 男性 /// </summary> Man, /// <summary> /// 女性 /// </summary> Women, /// <summary> /// 人妖 /// </summary> Shemale, /// <summary> /// 未知 /// </summary> UnKnow, }
值类型变量a,和引用类型变量stu所引用的实例内存概况如下图
引用类型有行为、有多态、有继承,而值类型无多态无继承。可以发现只要用到struct的场合,基本都可以用class替代。那么为什么还要有值类型呢?答案显而易见是效率问题。我们知道引用类型分配在堆上,而堆上的每个对象都有额外的一些成员(同步索引块,类型对象指针(指向类型对象的方法表)),这些都要初始化;另外从托管堆上分配一个对象,可能强制执行一次垃圾回收操作。由上可见软件系统的所有类型全是引用类型,那么引用程序的性能会显著下降。而值类型通常分配在栈上,通常为较小的带有数值含义的数据结构,访问的时候不需要像访问对象那样通过引用类型变量查找,使用完也是自动释放,这样效率就会很高。
通常定义类型的时候应该优先考虑值类型,因为它的效率更高。值类型一般在以下场合使用:
1类型本身数据量较小,且主要用于存储数据,表现出明显的数值含义。
2类型不需要从其他任何类型继承,也不派生出任何其他类型
相反,选用引用类型的时候会考虑其 1本身数据结构较大;2可能会扩展(即会派生)。目前个人知识有限,貌似也只能想到这两点。
1概念:装箱与拆箱,就是值类型与引用类型的转换。装箱就是类型数据转换为引用对象,是的可以将之类型是为对象来处理,通常转换为Object类型的或者该值类型实现的任何接口引用类型;拆箱就是引用类型转换为值类型,通常伴随着从堆中复制对象的数据字段的操作。注:只有被装过箱的对象才能被拆箱。
2先看一段代码
static void Main(string[] args)
{
int x = 100;
object o = x;//装箱
int y = (int) o;//拆箱
}
装箱过程三步曲:
拆箱过程两部曲
总结:装箱拆箱会带来大量的性能损失,我们平时写程序的时候应尽可能用FCL提供的重载方法或者泛型。如大家经常用的StringBuilder 用来拼接大量的字符串 比用"+"性能要高的多。
----------------------------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流!------------------------------