对与ref和out的区别,我相信很多人都知道,这里我简单罗列下:

1.首先ref和out两种类型的参数都是可以将方法内对参数的修改传递到方法外面

2.ref参数需要在传递之前初始化,out不需要,out参数在返回时必须赋值

3.在CLR角度看ref和out没什么区别,但是C#编译器采取不同的方式对待

下面通过一些实例来进一步了解

①一般方法传参

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TestParas tp = new TestParas();
Int32 a = 300;
String b = "wan";
String ret = tp.Add(a, b);
Console.WriteLine(ret);
}
} public class TestParas
{
public String Add(Int32 a, String b)
{
return a.ToString() + b;
} }
}

上面是非常普通,常见的传参。查看IL:

.method private hidebysig static
void Main (
string[] args
) cil managed
{
.entrypoint
.locals init (
[0] class ConsoleApplication1.TestParas tp,
[1] int32 a,
[2] string b,
[3] string 'ret'
) IL_0000: nop
//下面两行定义了一个tp的引用类型的实例,这里创建一个对象,并把对象的引用入栈
IL_0001: newobj instance void ConsoleApplication1.TestParas::.ctor()
IL_0006: stloc.0 //这里会有一个出栈,把出栈的值存在本地变量里,也就是这里的tp
IL_0007: ldc.i4 300 //这里定义一个值类型,先将提供的值入栈
IL_000c: stloc.1 //出栈,将值存在本地变量a中
IL_000d: ldstr "wan" //这里定义一个引用类型,将对该字符串的引用存入元素据
IL_0012: stloc.2 //取出当前栈的值放到本地变量b中
IL_0013: ldloc.0
IL_0014: ldloc.1
IL_0015: ldloc.2
IL_0016: callvirt instance string ConsoleApplication1.TestParas::Add(int32, string)//这里调用add方法,并传入两个参数
IL_001b: stloc.3
IL_001c: ldloc.3
IL_001d: call void [mscorlib]System.Console::WriteLine(string)
IL_0022: nop
IL_0023: ret
}

接下来看看add方法的IL:

下面改变代码,传入带ref和out的:

这时对应的IL也发生了变化,变化的部分如图:

这里跟C语言里面的一种传参方式相同,传递的是地址。接着看下Add方法的IL:

这里可以看到,在Add方法里定义了两个地址,分别对应传入的a,b的地址。所以在这里操作是针对a,b的地址操作,当然也就能将参数的变化传递到方法外。

为了效果明显,可以使用一个交换两个数的方法来展示:

运行结果为:

最后,给个结论吧:老赵的说法正确

ps:在默认情况下,CLR假定所有的方法参数传递的仅仅是值。当然除了加了ref和out以外。

今天看到有不少朋友在评论给了不少这方面的理解,还有一些扩展的例子,非常感谢,对我很有帮助。我觉得还可以挖掘一下,看下面的例子:

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Name = "初始值";
person.Age = 24;
Int32 a = 24;
ProcessPerson proc = new ProcessPerson();
Console.WriteLine("姓名:" + person.Name + " 年龄:" + person.Age + " a:" + a);
proc.Change(person,ref a);
Console.WriteLine("姓名:" + person.Name + " 年龄:" + person.Age + " a:" + a);
}
} public class Person
{
public String Name { get; set; }
public Int32 Age { get; set; }
} public class ProcessPerson
{
public void Change(Person obj,ref Int32 a)
{
obj.Name = "被修改";
obj.Age = 25;
a = 25;
}
}
}

首先说明下,这里Change方法的Person obj参数,加不加ref都会返回被修改的值。这里的obj是一个引用类型,里面包括Name,Age属性分别是引用类型和值类型。这里对它们的修改是传递到了方法外的。而对应的值类型a参数,则会在加了ref后发送改变。

所以这里我推测:首先,CLR默认对所有参数传递是值传递,所以这里应该成立,obj是一个引用类型。这里传递的应该obj包含的值(这里的值包含String类型的Name和Int32类型Age)。如果对obj的Name和Age修改,则在返回后在Main方法里面,打印出来的是修改之后的Name和Age的值。这是我的理解,还请路过的朋友多提自己的看法。

ref和out,以及一般方法的引用参数和值参数寻解的更多相关文章

  1. C#方法的六种参数,值参数、引用参数、输出参数、参数数组、命名参数、可选参数

    方法的参数有六种,分别是值参数.引用参数.输出参数.参数数组.命名参数.可选参数. 值参数 值参数是方法的默认类型,通过复制实参的值到形参的方式把数据传递到方法,方法被调用时,系统作两步操作: 在栈中 ...

  2. Ref 与 Out 的使用方法及区别

    C# 中我们有的时候会遇到这样的情况,一个方法需要返回多个参数的时候.怎么办呐? 我们可以给返回的参数加上 Out  或  Ref 类型标识  就可以实现返回多个参数了. 具体他们两个的用法有什么区别 ...

  3. C#方法参数--值参数,引用参数,输出参数

    值参数: 使用值参数,通过复制实参的值到形参的方式,把数据传递到方法,方法被调用的时候,系统做如下操作: 在栈中为形参分配空间: 复制实参到形参. 注意:一个值参数的实参不一定是变量,它可以是任何能够 ...

  4. C#中引用参数ref和输出参数out

    引用参数 用于按引用传递自变量. 为引用参数传递的自变量必须是具有明确值的变量,并且在方法执行期间,引用参数指明的存储位置与自变量相同. 引用参数使用 ref 修饰符进行声明. 输出参数 用于按引用传 ...

  5. lambda方法的引用与构造方法引用

    方法的引用 /** * @auther hhh * @date 2018/12/29 22:37 * @description */ public class ObjectMethodUse { /* ...

  6. C#总结---方法的out参数和ref参数

    我们知道,在c#中,当我们在一个方法中想要访问另一个方法中的变量的时候,有两种解决方案---参数和返回值.但当需要返回多个值,并且是不同类型的值的之后应该怎么办呢?解决方案可以是 (1)将所有类型数据 ...

  7. Java学习:方法的引用

    方法引用(Method references) lambda表达式允许我们定义一个匿名方法,并允许我们以函数式接口的方式使用它.我们也希望能够在已有的方法上实现同样的特性. 方法引用和lambda表达 ...

  8. java 方法及引用数据类型

    一.方法 在java中,方法就是用来完成解决某件事情或实现某个功能的办法. 1.语法格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,......){ 执行语句 ……… re ...

  9. 实例对比剖析c#引用参数的用法

    c#引用参数传递的深入剖析值类型的变量存储数据,而引用类型的变量存储对实际数据的引用.(这一点很重要,明白了之后就能区分开值类型和引用类型的差别) 在参数传递时,值类型是以值的形式传递的(传递的是值, ...

随机推荐

  1. 浅谈 zookeeper 原理,安装和配置

    当前云计算流行, 单一机器额的处理能力已经不能满足我们的需求,不得不采用大量的服务集群.服务集群对外提供服务的过程中,有很多的配置需要随时更新,服务间需要协调工作,那么这些信息如何推送到各个节点?并且 ...

  2. VBS 批量修改多个文件夹下的文字命名

    Function FilesTree(sPath)      Set oFso = CreateObject("Scripting.FileSystemObject")       ...

  3. 缺少对象 WScript 问题解决方法

    方法一: 先把脚本保存起来(保证你的脚本能正确运行),例如命名为test.vbs 然后在QTP写以下脚本就可以正确运行了! Dim oShell Set oShell =CreateObject (& ...

  4. WCF:调用方未由服务器进行身份验证

    错误描述: 1. WCF:调用方未由服务器进行身份验证 2. 无法处理消息.这很可能是因为操作“http://tempuri.org/ISCCLSvc/GetCarriersByWareHouse”不 ...

  5. nefu 449 超级楼梯 &&nefu 911 跨楼梯

    nefu 449 超级楼梯 Description 有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? Input 输入数据首先包含一个整数N,表示测试实例的 ...

  6. 认识cookie与session的区别与应用

    通常我们所说的浏览器自动保存密码,下次不用登陆,网页换皮肤,用户引导,提示一次就不再出现的内容,大部分通过cookie或者session来实现的,在这次制作用户引导中,本人就用到了cookie的内容, ...

  7. java动态代理(1)

    来源:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html# java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代 ...

  8. 【裸最小生成树】 模板 poj 1258

    #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #def ...

  9. java设计模式案例详解:代理模式

    代理模式就是用一个第三者的身份去完成工作,其实际意义跟字面意思其实是一样的,理解方式有很多,还是例子直观. 本例的实现类是实现买票功能,实际应用想要添加身份验证功能,利用代理模式添加验证步骤.上例子: ...

  10. 怎样将MySQL数据库上传到服务器

    首先,需要将本地的数据库导出来,作为一个数据文件,以备稍后上传到服务器用,在本地登陆phpmyadmin控制面板: 登陆成功后,在左侧选择需要操作的数据库: 选择后,页面会自动刷新,然后再在右边点击[ ...