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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黄星星 初级黑马   /  2013-3-15 16:23  /  1469 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

out参数与ref参数有何异同

评分

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

查看全部评分

3 个回复

倒序浏览
out是在函数内部赋值,然后返回结果给调用者;
ref是在函数内改变传递进来的参数,然后返回结果给调用者。
两者都是引用传递。

评分

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

查看全部评分

回复 使用道具 举报
下面分别对out和ref的使用方法根据实例进行说明

    第一个实例中,自己写MyTryParse方法,采用out关键字返回转换成功后int数值number。

        /// <summary>

        /// 写MyTryParse熟悉out关键字用法

        /// </summary>

        /// <param name="str">字符串</param>

        /// <param name="number">转换后输出值</param>

        /// <returns>是否转换成功</returns>

        public static bool MyTryParse(string str, out int number)

        {

            bool isOk = false;

            number = 0;

            try

            {

                number = Convert.ToInt32(str);

                isOk = true;

            }

            catch

            {



            }

            return isOk;

        }

    此函数实现功能与int.TryParse方法形同,将输入的字符串转换为int类型,若是转换成功,返回bool类型true,并同时返回转换后的int数值,若是转换失败,返回bool类型false,默认转换后数值为0。

    此例子采用out关键字将转换后的数值进行返回,在一个函数中,实现了返回多个返回值。



    第二个实例中,写FaKuan方法,要求罚款时,要求当月工资减500,同时年终奖减1000,函数调用完成后主函数变量值发生改变。

        static void Main(string[] args)

        {

            double salary = 5000;

            double nianZhongJiang = 20000;

            FaKuan(ref salary, ref nianZhongJiang);

            Console.WriteLine(salary);

            Console.WriteLine(nianZhongJiang);

            Console.ReadKey();

        }



        /// <summary>

        /// 此函数定义罚款规则,工资减500,同时年终奖减1000

        /// </summary>

        /// <param name="s"></param>

        /// <param name="nzj"></param>

        public static void FaKuan(ref double s, ref double nzj)

        {

            s -= 1000;

            nzj -= 1000;

        }

    通过使用ref关键字后,成功实现调用函数中变量值改变,ref的功能为将实参带入方法,方法运行结束后将值再带回调用函数。

评分

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

查看全部评分

回复 使用道具 举报
前者out,顾名思义,是为了输出,而后者ref是引用,是为了传入参数,二者设计意图不同那么使用的时候,就需要按照原本的意图去使用。由于意图不同,那么使用的时候也就有所差别,前者为了输出,那么就不必要保证在传入参数之前进行初始化,而后者由于目地是为了出入参数后使用,那么就必须保证传入参数之前进行初始化操作。这里,就从编译器这一块保证我们程序是正确的。
从clr角度来讲,二者是无差别的,行为是相同的。因为二者本质上讲都是传入了原来参数的地址,然后,直接操作该地址指向的空间。也就是说,假设原来的参数值值类型的,那么改值类型在堆栈上申明,初始化之后,会将该地址传给那个函数,然后,在该函数中,直接使用该地址对 对应空间进行操作。
我们在调用的时候,也需要指明类型,这样我们能够很明确的知道调用该参数的意图是什么(据说这也是C#设计者的意图)。
我们也可以通过out和ref来重载方法,但是仅通过out和ref来区分是不合法的,因为他们经过jit编译后代码是相同的。
Class Point

         Staticvoid Add(Point p){}
         Staticvoid Add(ref p){}
//      Staticvoid Add(out p){}//和上边的只能选其一


还有一个问题是,使用引用传入参数时,必须保证传入的参数类型的必须完全一致,比如说,
String str=”hello”;
GetObj(str);

Void GetObj(out object ob)

         Ob=newString(“000”);

是无法通过编译的,这样,确保了类型安全,防止因为传入参数传出后类型发生变化,之后的方法调用失败。

以前写代码的时候,常常使用ref去对参数进行改变,然后获取使用,沿袭了C++的思想,现在看来,应该严格按照原本的语言意图去写,这样,才能使代码更加健壮。

评分

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

查看全部评分

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