A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 陈君 金牌黑马   /  2014-5-17 18:48  /  1202 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 陈君 于 2014-5-17 23:11 编辑

out和ref有什么区别啊?他们都是可以用来在调用参数的时候的参数类型,而且他们都能改变实参的值的吧。那他们的区别在哪里呢?有点搞不清楚了

下面附上程序
   void swap(ref int a, ref int b)
        {
            int tmp;
            tmp = a;
            a = b;
            b = tmp;
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            int x = 3;
            int y = 4;
            string s = "2323";
            button1.Text = s;
            swap(ref x,ref y);
            MessageBox.Show("x="+x.ToString()+",y="+y.ToString());
            int.TryParse(button1.Text,out y);
        }
运行后MessageBox输出的x=4,y=3;而如果在int.TryParse(button1.Text,out y);这句的后面加上断点看下局部变量就会发现b=2323了说明了他们都能改变实参的值。那区别又在哪里呢?

评分

参与人数 1技术分 +1 收起 理由
czwanglei + 1

查看全部评分

7 个回复

倒序浏览
方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
当希望方法返回多个值时,声明 out 方法非常有用。使用 out 参数的方法仍然可以返回一个值。一个方法可以有一个以上的 out 参数。
若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。
不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。
属性不是变量,不能作为 out 参数传递。

方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。
传递到 ref 参数的参数必须最先初始化。将此方法与 out 参数相比,后者的参数在传递到 out 参数之前不必显式初始化。
属性不是变量,不能作为 ref 参数传递。

//上面的理解起来非常不好理解。下面我说说我自己的看法。

首先:两者都是按地址传递的,使用后都将改变原来的数值。很多人在论坛上解释说out是按数值传递,是错误的。简单的测试后可以知道out使用也能改变数值的,所以肯定是按照地址传递的。
其次:rel可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所以你必须初始化一次。这个就是两个的区别,或者说就像有的网友说的,rel是有进有出,out是只出不进。经典!!!



【如果能解决你的疑惑   就把问题 修改为   提问结束  谢谢了】

评分

参与人数 1技术分 +1 收起 理由
czwanglei + 1

查看全部评分

回复 使用道具 举报
ref必须初始化,out则是内部为外部赋值,所以不需初始化,而且外部初始化也没有用。
回复 使用道具 举报
ref是传入传出参数,用了ref每次对变量的修改都是修改原来变量的引用地址,不过不引用ref的话只是对原有变量的副本进行操作,而原有的变量本身没有发生改变。out和ref大部分相同,不同的是,out在使用是是必须赋初始值,如果不赋初始值的话将会报错,你可以试一下。out一般只用于传出参数。

评分

参与人数 1技术分 +1 收起 理由
czwanglei + 1

查看全部评分

回复 使用道具 举报
两个都是引用类型。ref在使用前必须赋值,out在使用后必须赋值。这句话比较抽象,可以看看老师的基础视频,里面讲的比较详细。
回复 使用道具 举报
czwanglei 发表于 2014-5-17 22:12
两个都是引用类型。ref在使用前必须赋值,out在使用后必须赋值。这句话比较抽象,可以看看老师的基础视频, ...

下面是晚上自己实验出来的一下心得。版主看看我最后得到的结论有没有错。
这是我晚上自己写的博文。地址是:http://blog.sina.com.cn/s/blog_db23a6350101mjjk.html

今天突然看到ref和out。对于初次接触这两个关键字的我很是困惑。于是就去找了下它们的用法和区别。下面说下我的研究成果。
ref和out的共同点是传递参数都是按引用来传递的。通俗点说就是他们都能改变实参的值。如果学过C语言的话应该就知道一个传值调用和传址调用的问题。而所谓的引用就好像C语言里的传址调用。举个最经典的C语言里用来分析传值和传址调用区别的程序。

然后我们运行下。运行后MessageBox输出的x=4,y=3;而如果在int.TryParse(button1.Text,out y);这句的后面加上断点看下局部变量就会发现b=2323了说明了他们都能改变实参的值。 那么他们的区别在哪里呢?
ref要求实参必须在传递之前进行初始化。而out则不需要,但是out必须在方法返回前对以out方式的实参进行赋值。
看到ref的实参必须先进行初始化的时候我产生了一个问题。比如int a;是定义了一个int类型的变量。我们都知道,如果直接这样写的话a的值=0;那这个时候a能不能作为初始传入swap函数呢?它不是已经有了初值了嘛?a是不是算是已经初始化了呢?

从这里我知道了虽然x已经有值并且为了。但是它不算结果了初始化。那么怎么样才算是初始化了呢?
这里我又定义了一个类

然后定义了一个swap2的函数并调用了它。

在用swap2之前我先o a=new o();然后才调用了。那如果我把new o();去掉呢?然后就发现swap2不能调用了,提示是使用了未赋值的局部变量a.
这里我不经去想。这个对象我们不是已经创建了嘛?而且这个对象里面的a,b两个字段我都已经赋值了啊?为什么还说我未赋值?
然后再想想new这个词,老师总是说用new来动态分配内存。内存!对了内存,发现问题所在了,如果我们没new的话系统可能不会去分配内存给我们的这个对象。又如何去引用呢?所以所谓的初始化应该就是分配内存。
但是int a=3;这样也没有用new啊?这里我的理解是对int型变量进行赋值的时候系统其实在帮我们分配内存后如何在赋值的。不然这个变量怎么存储数据呢?
这样一来out为什么要在方法返回前对out进行赋值也就说的通了。因为不要求调用方法前对实参进行初始化,如果不赋值的话,那么这个实参根本就还没分配到内存,又谈何返回给实参呢?





点评

不错,很好,加油。  发表于 2014-5-18 08:37
分析得很细,不错!  发表于 2014-5-17 23:28

评分

参与人数 2技术分 +7 收起 理由
张文 + 5 非常给力.
czwanglei + 2

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马