zoukankan      html  css  js  c++  java
  • C#中关键字ref与out的区别(转)

    在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#中,方法的参数传递有四种类型:传值(by value),传址(by reference),输出参数(by output),数组参数(by array)。传值参数无需额外的修饰符,传址参数需要修饰符ref,输出参数需要修饰符out,数组参数需要修饰符params。传值参数在方法调用过 程中如果改变了参数的值,那么传入方法的参数在方法调用完成以后并不因此而改变,而是保留原来传入时的值。传址参数恰恰相反,如果方法调用过程改变了参数 的值,那么传入方法的参数在调用完成以后也随之改变。实际上从名称上我们可以清楚地看出两者的含义--传值参数传递的是调用参数的一份拷贝,而传址参数传 递的是调用参数的内存地址,该参数在方法内外指向的是同一个存储位置。

    (转自http://www.cnblogs.com/windinsky/archive/2009/02/13/1390071.html)

  • 相关阅读:
    网络文件传输方式
    ETL利器Kettle
    oracle 字符处理
    ORACLE临时表空间
    Count(*)或者Count(1)或者Count([列]) 区别
    Oracle trunc()函数的用法
    DATE 日期格式
    oracle 异常
    物化视图
    域名和端口
  • 原文地址:https://www.cnblogs.com/guanjie20/p/1618570.html
Copyright © 2011-2022 走看看