在C#中,ref与out是很特殊的两个关键字。使用它们,可以使参数按照引用来传递。
总的来说,通常我们向方法中传递的是值.方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不将受到影响.此外我们还有其他向方法传递参数的形式,引用(ref)和输出(out).
有时,我们需要改变原来变量中的值,这时,我们可以向方法传递变量的引用,而不是变量的值.引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值.变量的值存储在内存中,可以创建一个引用,他指向变量在内存中的位置.当引用被修改时,修改的是内存中的值,因此变量的值可以将被修改.当我们调用一个含有引用参数的方法时,方法中的参数将指向被传递给方法的相应变量,因此,我们会明白,为什么当修改参数变量的修改也将导致原来变量的值.
通俗的从功能上来讲,使用这两个关键字,可以使一个方法返回多个参数。
MSDN中的定义:
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
 out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。

首先,我们来看一个简单的例子:

        static void TestRefAndOut()
        {
            string s1 = "Good Luck!";
            TestRef(ref s1);
            Console.WriteLine(s1);//output: Hello World!
        }
        static void TestRef(ref string str)
        {
            str = "Hello World!";
        }

在TestRefAndOut()中将字符串s1以ref关键字的方式传到方法TestRef(ref string str)中,在这个方法中,我们改变了s1的引用变量str的值,最后,回到TestRefAndOut()方法后输出s1的值,发现其值已被改变。

将上例中的ref换成out,代码如下:

        static void TestRefAndOut()
        {
            string s1 = "Good Luck!";
            //TestRef(ref s1);
            TestOut(out s1);
            Console.WriteLine(s1);//output: Hello World!
        }

static void TestOut(out string str)
        {
            str = "Hello World!";
        } 

同样,在将ref换成out后,会发现最后的输出仍然是相同的,那这两个关键字的区别是什么呢?

进一步测试:

ref:

        static void TestRefAndOut()
        {
            string s1 = "Good Luck!";
            TestRef(ref s1);
        }

static void TestRef(ref string str)
        {
            Console.WriteLine(str);//output: Good Lick!            
        }

out

        static void TestRefAndOut()
        {
            string s1 = "Good Luck!";
            TestOut(out s1);
        }

static void TestOut(out string str)
        {
            Console.WriteLine(str);//compile does not pass
        }

ref的那段代码顺利编译,输出"Good Luck!",而out那段代码却无法通过编译,提示“Use of unassigned out parameter 'str' ”,即使用了未分配地址的out参数str。怎么回事呢?

原来out参数在进入方法的时候,C#会自动清空它的一切引用和指向,所以在上面的out例子中,必需先要为str参数赋值。如以下程序。

        static void TestRefAndOut()
        {
            string s1 = "Good Luck!";
            TestOut(out s1);
        }
        static void TestOut(out string str)
        {
            str = "Hello World!";
            Console.WriteLine(str);//output: Hello World!
        }

Ok,得到第一个区别: out 参数在进入方法(函数)时后清空自己,使自己变成一个干净的参数,也因为这个原因必须在方法返回之前或再使用out参数前为 out 参数赋值(只有地址没有值的参数是不能被.net接受的);而ref参数是不需要在被调用方法使用前先赋值的,甚至也可以被调用方法中不改变ref参数的值,这都不会引起编译错误。

在继续看一段代码:

ref:

        static void TestRefAndOut()
        {
            string s1;
            TestRef(ref s1);
            Console.WriteLine(s1);//compile does not pass!
        }
        static void TestRef(ref string str)
        {
            str = Hello World!";
        }    
out:
        static void TestRefAndOut()
        {
            string s1;
            TestOut(out s1);
            Console.WriteLine(s1);//output: Hello World!
        }

static void TestOut(out string str)
        {
            str = "Hello World!";
        }   

这回发现,ref这段代码无法编译了,s1是一个空引用,所以无法使用。而out参数则因为上述的那个原因,它不在乎s1是不是空引用,因为就算s1不是空引用,它也会把s1变成空引用的。Ok,第二个区别:ref参数在使用前必需初始化,而out不需要。嗯,由上边两个区别可以引申一下,out参数只进不出,ref参数有进有出。在用法上概括一下就是:out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。

C#中关键字ref与out的区别【转】的更多相关文章

  1. 简述C#中关键字var和dynamic的区别

    C#中关键字var和dynamic的区别如下: 1.var申明的变量必须初始化,dynamic申明的变量无需初始化. 2.var关键字只能在方法内部申明局部变量,dynamic关键字可用于局部变量,字 ...

  2. C#中的ref和out的区别

    转载原地址 http://www.cnblogs.com/gjahead/archive/2008/02/28/1084871.html ref和out的区别在C# 中,既可以通过值也可以通过引用传递 ...

  3. Spring框架xml配置中属性ref与value的区别

    1.spring批量扫描mybatis的mapper,使用value 2.spring管理mybatis的单个mapper,用的是ref 虽然引用的是同一个bean,但两个对象的属相类型明显不一样,一 ...

  4. Python中关键字global与nonlocal的区别

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xCyansun/article/details/79672634终于下定决心学习Python了.既然 ...

  5. Java中关键字super与this的区别

    一.super关键字 在JAVA类中使用super来引用父类的成分,用this来引用当前对象,如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象.怎么去引 ...

  6. 转载 Python中关键字global与nonlocal的区别

    转载自CSDN 雁丘1990, 原文地址: https://blog.csdn.net/xcyansun/article/details/79672634 这篇文章写的很赞, 条理清晰, 分析循序渐进 ...

  7. C#中关键字ref修饰类对象或结构体[转]

    using System; using System.Collections.Generic; using System.Text; namespace CSharpTest { struct Dog ...

  8. Java中关键字throw和throws的区别

    ==========================================题外话===================================================== 今 ...

  9. .net 中 ref out params的区别

    C#中有三个关键字-ref,out ,params,虽然本人不喜欢这三个关键字,因为它们疑似破坏面向对象特性.但是既然m$把融入在c#体系中,那么我们就来认识一下参数修饰符ref,out ,param ...

随机推荐

  1. 剑指offer-面试题.二叉树的镜像

    题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像.  二叉树节点定义如下: strcut BinaryTreeNode { int val; strcut BinaryTreeNode* m_ ...

  2. mysql命令具体解释

    首先创建一个简单的user表 CREATE TABLE `user` ( `id`  int NOT NULL AUTO_INCREMENT , `name`  varchar(255) NULL , ...

  3. PHP流程控制中不经常使用的替代语法

    准备做个wordpress的主题.结果看到了例如以下的语法: <div id="primary" class="content-area"> < ...

  4. SSH2配置事务的两种方式

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  5. NET基础课--WinForm开发推荐3

    用户体验 较长时间的运算:使用进度条(progress bar) 不要阻塞界面(UI)线程:使用多线程进行长时间的运算 状态栏(status bar)提示应用程序的状态 操作开始之后,用户应当能够通过 ...

  6. 易语言转C#小试牛刀

    呵呵,用了几年的易语言,太郁闷了,玩过E的童鞋们懂得,偶然机会尝试C#,现正式投入C#门下. 我会把我学习C#的一些知识和重点,实时发不到我的BLOG中,同想学习C#的童鞋一起成长起来.

  7. 11个有用的移动网页开发App和HTML5框架

    在过去的两年里,触屏设备飞速增长.iOS和Android设备让开发者和设计师开始重新思考他们的网页应用,以提供更好的触屏体验. 移动Web应用相对于本地的App有很多优势,虽然也有很多设计和开发上的挑 ...

  8. html5的改变

    html5的改变 新增的元素 新增的结构元素 section.article.aside.header.hgroup.footer.nav.figure 新增的其他元素 video.audio.emb ...

  9. 封装一些数据库SQLCipher的方法(增、删、改、查)

    上一篇随笔只是简单的说了一下使用SQLCipher框架,介绍的比较笼统,可能看一遍之后更加蒙圈了,为了更好的使用这个数据库,整理了我在公司项目的需要用的方法,包括创建表,插入数据,更新数据,搜索查询数 ...

  10. Android中Menu的基本用法

    一. 使用xml定义Menu 菜单资源文件必须放在res/menu目录中.菜单资源文件必须使用<menu>标签作为根节点.除了<menu>标签外,还有另外两个标签用于设置菜单项 ...