C#引用传递[转]
学过C#的人都知道,通过值或通过引用,值类型和引用类型都可以作为方法参数传递。在C#中,不管是值类型或者是引用类型,所有方法参数在默认情况下是通过值传递的。
1)通过值传递值类型
在通过值传递作为方法参数的变量时,传递给方法的是数据副本。在方法中对该数据的任何修改都不会对初始值有任何影响。
C#如下代码:
- using System;
- class MyExecutableClass
- {
- static void Main(string[] args)
- {
- int value=50;
- DoSometing(value);
- Console.WriteLine(value);
- }
- static void DoSomething(int parameter)
- {
- parameter=100;
- }
- }
程序的输出为50.也许你会感到奇怪,为什么不是100呢?因为变量value是通过值而不是引用传递的。我们不需要添加任何特殊的关键字,而是依赖于C#的默认行为,通过值传递值类型。
通过引用传递值类型,也就是说传递值(变量)的引用。如果传递引用的话,那么无论在程序的什么地方作改变的话(可能是在另一个方法、属性中,甚至是另一个对象中),都会改变使用改引用的值。对方法中任何参数的改变都将影响方法的返回值。
在C#中,通过引用传递是通过ref关键字实现的,必须按如下所示将ref关键字添加到方法定义中:
static void DoSomething(ref int parameter)
在传递参数时,必须使用ref关键字。
DoSomething(ref value)
下面的代码演示了如何对值类型使用ref关键字:
- using System;
- class MyExecutableClass
- {
- static void Main(string[] args)
- {
- int value=50;
- DoSomething(ref value);
- Console.WriteLine(value);
- }
- static void DoSomething(ref int parameter)
- {
- parameter=100;
- }
- }
结果正如你所料,输出为100.
3)通过值传递引用类型
一般来说,通过值传递意味着传递存储在栈中的值。对于引用类型来说,存储在栈上的值表示对
内存中对象实际位置的引用。因此,如果通过值传递引用类型,就意味着传递的是对象的引用(它的堆栈)
.使用该引用作的改变最终会改变堆中的同一对象。
通过值传递引用类型不像通过值传递值类型---它更像通过引用传递值类型。在如下代码中,
我们将Person用作引用类型。
- using System;
- class MyExecutableClass
- {
- static void Main(string[] args)
- {
- Person person=new Person(50);
- DoSomething(person);
- Console.WriteLine(person.Age);
- }
- static void DoSomething(Person somePerson)
- {
- somePerson.Age=100;
- }
- }
- class Person
- {
- public int Age;
- public Person(int Age);
- {
- this.Age=Age;
- }
- }
运行程序,可以发现输出值为100.
如果对DoSometing方法作如下修改;
- static void DoSomething(Person somePerson)
- {
- somePeron=new Person(100);
- }
重新运行程序,发现输出为50.这是因为我们并没有将引用传递给方法?
答案是:不,我们确实发送了引用。引用类型有两个元素---引用和对象。现在,在
调用DoSomething()方法时,我们创建了一个引用副本,它仍然指向同一对象,因此,对对象的改变会影响主程序。而对引用的改变则不会,在方法结束时,消失的只是引用的副本。
1。在使用somePerson.Age属性改变年龄时,我们改变的是对象。
2。但接下来是创建一个新对象,改变引用来指向它---对引用的改变将会丢失。
应该怎么做呢?方案就是通过引用传递引用类型,那样作的话,如果改变somePerson所存储的引用,那么另一个“父”引用会自动更新。听起来很混乱,下面再讨论。
我们知道,在通过值传递引用类型时,我们传递对内存中对象位置的引用。而通过引用传递引用类型时,我们将传递引用的引用。
下面例子就是说明通过引用传递就很有用。
- <pre name="code" class="csharp"></pre><pre name="code" class="csharp">using System;
- class MyExecutableClass
- {
- static void Main(string[] args)
- {
- Person person=new Person(50);
- DoSometing(ref person);
- Console.WriteLine(person.Age);
- }
- static void DoSometing(ref Person somePerson)
- {
- somePerson=new Person(100);
- }</pre><pre name="code" class="csharp">} </pre>
- <pre></pre>
这次输出为100;person变量实际上对堆上Person对象的引用。在调用DoSomething()时,编译器创建了对Person引用的引用(而不是对Person对象的引用).在DoSometing()方法中,somePerson是Person引用的引用,而Person引用堆上的对象。然而,DoSomething()知道值是通过引用传递的,因此对somePerson的任何改变实际上是改变了person。结果就是somePerson的行为就好像它是person引用,而不是其副本。
附测试代码,加深理解:
static void CallDoType()
{
//传递值类型
int value = 50;
//DoValueTransferValueType(value);
//DoReferenceTransferValueType(ref value);
//Console.WriteLine(value);
//传引用类型 传类
Person person = new Person(50);
//DoValueTransferReferenceType(person);
DoReferenceTransferReferenceType(ref person);
Console.WriteLine(person.Age);
}
/// <summary>
/// 通过值传递值类型 在通过值传递作为方法参数的变量时,传递给方法的是数据副本。在方法中对该数据的任何修改都不会对初始值有任何影响。
/// </summary>
/// <param name="parameter"></param>
static void DoValueTransferValueType(int parameter)
{
parameter = 100;
}
/// <summary>
/// 通过引用传递值类型 在C#中,通过引用传递是通过ref关键字实现的
/// </summary>
/// <param name="parameter"></param>
static void DoReferenceTransferValueType(ref int parameter)
{
parameter = 100;
}
/// <summary>
/// 通过值传递引用类型 一般来说,通过值传递意味着传递存储在栈中的值。对于引用类型来说,存储在栈上的值表示对内存中对象实际位置的引用。
/// </summary>
/// <param name="parameter"></param>
static void DoValueTransferReferenceType(Person somePerson)
{
//somePerson.Age = 100; // 输出100
//引用类型有两个元素---引用和对象。现在,在调用DoSomething()方法时,我们创建了一个引用副本,它仍然指向同一对象,因此,对对象的改变会影响主程序。
//而对引用的改变则不会,在方法结束时,消失的只是引用的副本。
somePerson = new Person(100); //输出50:
/*1。在使用somePerson.Age属性改变年龄时,我们改变的是对象。
2。但接下来是创建一个新对象,改变引用来指向它---对引用的改变将会丢失。
应该怎么做呢?方案就是通过引用传递引用类型,那样作的话,如果改变somePerson所存储的引用,那么另一个“父”引用会自动更新*/
}
/// <summary>
/// 通过引用传递引用类型
/// 在通过值传递引用类型时,我们传递对内存中对象位置的引用。而通过引用传递引用类型时,我们将传递引用的引用。
/// </summary>
/// <param name="parameter"></param>
static void DoReferenceTransferReferenceType(ref Person somePerson)
{
somePerson = new Person(100);
}
class Person
{
public int Age;
public Person(int Age)
{
this.Age = Age;
}
}
C#引用传递[转]的更多相关文章
- Java 为值传递而不是引用传递
——reference Java is Pass by Value and Not Pass by Reference 其实这个问题是一个非常初级的问题,相关的概念初学者早已掌握,但是时间长了还是容易 ...
- call_user_func()的参数不能为引用传递 自定义替代方法
php手册 中关于 请注意,传入call_user_func()的参数不能为引用传递. 关于这个情况的解释,可自己搜索.我们可以自己定义一个函数解决这样的问题,实例如下: <?php ini_s ...
- [转] C++的引用传递、指针传递参数在java中的相应处理方法
原文出处:[http://blog.csdn.net/conowen/article/details/7420533] 首先要明白一点,java是没有指针这个概念的. 但是要实现C++的引用传递.指针 ...
- python 引用传递与值传递
https://taizilongxu.gitbooks.io/stackoverflow-about-python/content/16/README.html 1.也就是如果传可变对象,就是引用传 ...
- java是值传递还是引用传递
首先写一个简便的Employee,以便测试使用. class Employee { private String name; public Employee(String name) { this.n ...
- Java中值传递和引用传递的概念
很多书中都提到了在Java中只存在值传递,但是今天在一个NanoHTTPD的源码中看到这样一段: if (qmi >= 0) { decodeParms(uri.substring(qmi + ...
- Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义
一.Java中什么叫做引用类型变量?引用:就是按内存地址查询 比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...
- java关于值传递和引用传递的有趣试验
上代码: public class Demo { public static void main(String[] args) { test_1(); test_2(); } public stati ...
- java中值传递和引用传递
最近工作中使用到了值传递和引用传递,但是有点懵,现在看了下面的文章后清晰多了.一下是文章(网摘) 1:按值传递是什么 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: public clas ...
- Java中的值传递和引用传递
这几天一直再纠结这个问题,今天看了这篇文章有点思路了,这跟C++里函数参数为引用.指针还是有很大区别. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里 ...
随机推荐
- CLR_Via_C#学习笔记之CLR的执行模型
1:公共语言运行时(Common Language Runtime,CLR)是一个可由多种编程语言使用的“运行时”.CLR的核心功能(比如内存管理.程序集加载.安全性.异常处理和线程同步)可由面向CL ...
- 小米电视2S加量不加价,你还会买吗?
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...
- CallableStatement简单使用
直接上存储过程.函数 --运行不带參数但带返回值的存储过程 CREATE OR REPLACE PROCEDURE proc_getUserCount(v_totalCount OUT NUMBER) ...
- Oracle XE安装具体解释
一.原数据库的卸载 数据库的卸载就不多说了,讲一下过程: 1.运行Oracle Uninstall,卸载Oracle产品 2.删除regedit下的全部Oracle相关 ...
- 阿里云 部署并开启nodejs应用
1.下载资源 $ wget https://nodejs.org/dist/v8.11.2/node-v8.11.2-linux-x64.tar.xz 2.xz解压 $ xz -d node-v8. ...
- Cookie/Session编码
Unicode编码:保存中文 中文与英文字符不同,中文属于Unicode字符,在内存中占4个字符,而英文属于ASCII字符,内存中只占2个字节.Cookie中使用Unicode字符时需要对Unicod ...
- JUC组件扩展(三):BlockingQueue(阻塞队列)详解
一. 前言 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大 ...
- 设置CentOS控制台分辨率图文详解
最小化安装CentOS,默认是没有图形界面的,这个正合我意.但是命令行界面很小,会有很多输出被迫换行写,影响美观. 那么,怎样调整终端分辨率呢 解决方案:修改引导程序配置 /boot/grub/gru ...
- Atitit.js javascript异常处理机制与java异常的转换 多重catc hDWR 环境 .js exception process Vob7
Atitit.js javascript异常处理机制与java异常的转换 多重catc hDWR 环境 .js exception processVob7 1. 1. javascript异常处理机制 ...
- 安装wxWidgets遭遇的两大关卡
早就想体验wxWidgets.这学期的C++课,课时还算充裕.关键是弟子们的实践能跟得上,我希望能让他们也浅尝一把GUI开发. MFC能够选.但既然IDE都用CodeBlocks了.还是选wxWidg ...