值类型与引用类型

值类型:派生自System.ValueType类的类型是值类型,派生自ValueType的类型都会自动在栈(stack)上进行分配,因此有一个可预测的生命周期,而且非常高效。

引用类型:在继承链上没有System.ValueType的类型(如System.Type、System.String、System.Array、System.Exception以及System.Delegate)不会在栈上分配,而是在垃圾回收堆(heap)上进行分配。

另:C#中的所有基类型都是结构类型(例如:int对应System.Int32结构),结构类型是值类型;类类型是引用类型;栈的执行效率要比堆的执行效率高,可是栈的资源有限,不适合处理大的逻辑复杂的对象。所以结构处理作为基类型对待的小对象,而类处理某个商业逻辑;因为结构是值类型所以结构之间的赋值可以创建新的结构,而类是引用类型,类之间的赋值只是复制引用;(所以在以结构为参数传递时,最好使用ref,这样只传递地址引用,能够提高效率,同时也应注意这样结构的值也会随着方法调用而改变)

从功能上说,ValueType的唯一目的是"重写"由Object定义的虚方法来使用基于值而不是基于引用的语法:

public abstract class ValueType:object
{
protected ValueType();
public override bool Equals(object obj);
public override int GetHashCode();
public override string ToString();
}

由于值类型是基于值语法的,结构(包括所有数值数据类型如Int32等、自定义结构、枚举)的生命周期都是可预测的。但结构离开定义的作用域时,就会立即从内存中清除。

static void LocalValueType()
{
int i=0;//int是System.Int32结构
Point p=new Point();//Point是自定义结构
}
 //出了方法作用域,i与p被清除了(已经被弹出栈)。

值类型与类类型的赋值

当把值类型赋值给另外一个时,是对字段成员逐一进行复制。对于System.Int32这样简单的数据类型,唯一需要复制的成员就是数值。而对像Point复杂点的自定义结构,就需要把Point所有的字段复制到新的结构变量中。改变新的结构变量的字段的值不会影响原结构变量的字段值。

当对引用类型进行复制时,是把原引用变量的地址指向赋给新的引用变量,两个引用变量指向同一个对象。

View Code

//结构Point的定义
struct Point
{
public int X;
public int Y;
public Point(int XPos, int YPos)
{
X = XPos;
Y = YPos;
}
public void Increment()
{
X++; Y++;
}
public void Decrement()
{
X--; Y--;
}
public void Display()
{
Console.WriteLine("X = {0}, Y = {1}", X, Y);
}
}
//PointRef类型的定义
class PointRef
{
public int X;
public int Y;
public PointRef(int XPos, int YPos)
{
X = XPos;
Y = YPos;
}
public void Increment()
{
X++; Y++;
}
public void Decrement()
{
X--; Y--;
}
public void Display()
{
Console.WriteLine("X = {0}, Y = {1}", X, Y);
}
}
static void Main(string[] args)
{
Console.WriteLine("***** 值类型 / 引用类型 *****\n");
ValueTypeAssignment();
ReferenceTypeAssignment();
Console.ReadLine();
}
static void ValueTypeAssignment()
{
Console.WriteLine("指定值类型\n");
Point p1 = new Point(10, 10);
Point p2 = p1;
p1.Display();
p2.Display();
p1.X = 100;
Console.WriteLine("\n=> 改变 p1.X\n");
p1.Display();
p2.Display();
}
static void ReferenceTypeAssignment()
{
Console.WriteLine("指定引用类型\n");
PointRef p1 = new PointRef(10, 10);
PointRef p2 = p1;
p1.Display();
p2.Display();
p1.X = 100;
Console.WriteLine("\n=> 改变 p1.X\n");
p1.Display();
p2.Display();
}

包含引用类型的值类型

默认情况下,但值类型包含其他引用类型时,赋值将产生一个引用副本。这样就有两个独立的结构,每个都包含指向内存中同一个对象的引用(也就是浅复制)。当先执行深度赋值(将引用的对象的状态完全复制到新的对象中)时,引用类型就需要实现ICloneable结构。

View Code

class ShapeInfo
{
public string infoString;
public ShapeInfo(string info)
{ infoString = info; }
}
struct Rectangle
{
public ShapeInfo rectInfo;
public int rectTop, rectLeft, rectBottom, rectRight;
public Rectangle(string info, int top, int left, int bottom, int right)
{
rectInfo = new ShapeInfo(info);
rectTop = top; rectBottom = bottom;
rectLeft = left; rectRight = right;
}
public void Display()
{
Console.WriteLine("String = {0}, Top = {1}, Bottom = {2}, Left = {3}, Right = {4}",
rectInfo.infoString, rectTop, rectBottom, rectLeft, rectRight);
}
}
static void Main(string[] args)
{
Console.WriteLine("***** 值類型 / 引用類型 *****\n");
ValueTypeContainingRefType();
Console.ReadLine();
}
static void ValueTypeContainingRefType()
{
Console.WriteLine("-> 創建 r1");
Rectangle r1 = new Rectangle("初始的信息", 10, 10, 50, 50);

Console.WriteLine("-> 把r1賦給r2");
Rectangle r2 = r1;
Console.WriteLine("-> 改變r2的值");
r2.rectInfo.infoString = "新的字符信息!";
r2.rectBottom = 4444;
r1.Display();
r2.Display();
}

可以看出,当使用r2的引用改变信息字符串的值时,r1的引用显示了同样的值(r1的引用的值也改变了)。

按值转递引用类型与按引用转递引用类型

引用类型可以作为参数传递给类型成员。但是,按按值转递一个对象与按引用转递一个对象大有不同。

View Code

static void Main(string[] args)
{
//按值傳遞
Console.WriteLine("*********按值傳遞引用類型對象*****");
Car c = new Car("寶馬", 100);
Console.WriteLine("按值傳遞前對象的狀態。");
c.Print();
SendACarByValue(c);
Console.WriteLine("按值傳遞後對象的狀態。");
c.Print();
Console.ReadLine();
//按引用傳遞
Console.WriteLine("*********按值傳遞引用類型對象*****");
Car bmw = new Car("寶馬", 100);
Console.WriteLine("按引用傳遞前對象的狀態。");
bmw.Print();
SendACarByReference(ref bmw);
Console.WriteLine("按引用傳遞後對象的狀態。");
bmw.Print();
Console.ReadLine();

}
static void SendACarByValue(Car c)
{
//改變c的Speed屬性的值
c.Speed = 150;
//給c重新賦值(賦予新的Car對象的指向)
c = new Car("保時捷", 250);
}
static void SendACarByReference(ref Car c)
{
//改變c的Speed屬性的值
c.Speed = 150;
//給c重新賦值(賦予新的Car對象的指向)
c = new Car("保時捷", 250);
}
class Car
{
public int Speed { get; set; }
public string Name { get; set; }
public Car(string n, int s)
{
this.Name = n;
this.Speed = s;
}
public Car() { }
public void Print()
{
Console.WriteLine("汽車{0}的速度是{1}", this.Name, this.Speed);
}

}

可以看出:

一、如果按值传递引用类型,被调用者可能改变对象的状态数据的值,但不能改变所引用的对象(不能指向另一个新的对象,即指向没有改变)。

二、如果按引用传递引用类型,被调用者可能改变对象的状态数据的值和所引用的对象(指向都改变了)。

小结

值类型与引用类型的比较:

问题

值类型

引用类型

这个类型分配在哪里?

分配在栈(stack)上

分配在托管堆(heap)上

变量是怎么表示的?

是副本

变量指向被分配的对象所占的内存

能否作为其他类型的基类?

不能,是封闭(sealed)的

能,若没有声明是封闭时可以。

能为这个类型定义构造函数吗?

能,但默认的构造函数被保留

(即自定义构造函数必须全部带有参数)

这个类型的变量什么时候消亡?

当超出定义它们的作用域时

当托管堆被垃圾回收器回收时


转载于:https://www.cnblogs.com/bruce-wong/archive/2011/03/01/1967107.html

C#编程语言(七):值类型与引用类型相关推荐

  1. [你必须知道的.NET]第九回:品味类型---值类型与引用类型(中)-规则无边

    发布日期:2007.5.28 作者:Anytao ©2007 Anytao.com ,原创作品,转贴请注明作者和出处. 接上回[第八回:品味类型---值类型与引用类型(上)-内存有理]的探讨,继续我们 ...

  2. C#值类型与引用类型

    C#值类型与引用类型 值类型 存储的是实际的数据值. C#的值类型,包括整数型.实数型.逻辑型.字符型.枚举.结构等. 引用类型 本身不存储数据值,存储对这些实际数据的引用,也就是地址. 区别 值类型 ...

  3. 第八回:品味类型---值类型与引用类型(上)-内存有理

    第八回:品味类型---值类型与引用类型(上)-内存有理 http://www.cnblogs.com/anytao/archive/2007/05/23/must_net_08.html 发布日期:2 ...

  4. swift string转int_swift中结构体和类的区别(值类型和引用类型的区别)

    在swift中结构体和类有着更多的相同之处,在一般的使用中能够做到互相替换.我们可以先看看官方文档的描述: Unlike other programming languages, Swift does ...

  5. [你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途

    本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 [下载]:[类型示例代码] 1. 引言 值类型与引用类型的话题经过了两个回合([第八回:品味类型---值类 ...

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

    本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 1. 引言 买了新本本,忙了好几天系统,终于开始了对值类型和引用类型做个全面的讲述了,本系列开篇之时就是因 ...

  7. C# 值类型与引用类型(1)

    1. 主要内容 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 2. 基本概念 C#中,变量是值还是引用仅取决于其数据类型. C#的基本数据类型都以平台无关的方式来定义,C#的 ...

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

    引用自:http://www.cnblogs.com/anytao/category/155694.html 作者:Anytao 本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型 ...

  9. LV2之-----js 值类型和引用类型(基石1)

    一.学习目标 1.值类型和引用类型的基本概念 2.常见的值类型和引用类型都有哪些? 3.数据类型检测 4.值类型和引用类型在内存中的存储机制 5.创建对象的方式有哪些? 6.对象属性名的点表示法和方括 ...

最新文章

  1. 软件工程个人作业02
  2. esxi安装ghost win7_针对Win7远程桌面的攻击实践(完美)
  3. Interview:算法岗位面试—11.02早上上海某银行(上海分行,四大行之一)信息技术岗笔试记录
  4. 移动端 Web 开发踩坑之旅
  5. 文献记录(part78)--Structure-Constrained Low-Rank Representation
  6. Java状态和策略设计模式之间的差异
  7. Apache实验-目录别名
  8. 数据结构思维 第十七章 排序
  9. flask-bootstrap插件
  10. 多个 vCenter Server 实例部署的升级或迁移顺序以及混合版本转换行为
  11. 针对xml文件做提取与写入的操作
  12. 【RLchina第二讲】 Foundations of Reinforcement Learning
  13. nodejs 做后台的一个完整业务整理
  14. 如何监控防火墙后的流量?
  15. linux文本编辑器
  16. SLF4J user manual
  17. iOS 支付宝手机网站支付
  18. 刷百度权重那些不为人知的事情
  19. 【论】PISCES: A Programmable, Protocol-Independent Software Switch
  20. 【量化入门】通过几种常见的量化策略框架,学习量化炒股

热门文章

  1. python实训内容_Python实验课:Python元组数据及其运算
  2. Java笔记-AnnotationConfigApplicationContext在Spring中的例子
  3. 计算机图形学Web前端笔记-浏览器中心点转场景坐标理论及实现(two.js)
  4. canvas笔记-closePath函数的使用(含例子)
  5. java 8 java demo_Java 8 中的 Streams API Demo
  6. mac nginx php7 配置,mac os下配置nginx+php7.1+fastcgi
  7. java项目启动后运行方法_spring boot在启动项目之后执行的实现方法
  8. python数字排列组合去重_排列组合-生成集合的所有子集
  9. (王道408考研操作系统)第二章进程管理-第一节2:进程状态及其切换
  10. 用户模式下的线程同步