• C#中关键字ref与out的区别(原创)


    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。传值参数在方法调用过 程中如果改变了参数的值,那么传入方法的参数在方法调用完成以后并不因此而改变,而是保留原来传入时的值。传址参数恰恰相反,如果方法调用过程改变了参数 的值,那么传入方法的参数在调用完成以后也随之改变。实际上从名称上我们可以清楚地看出两者的含义--传值参数传递的是调用参数的一份拷贝,而传址参数传 递的是调用参数的内存地址,该参数在方法内外指向的是同一个存储位置。

    上边的就是这两个参数在应用上的区别,希望对大家有用!

  • 相关阅读:
    springboot文件上传: 单个文件上传 和 多个文件上传
    Eclipse:很不错的插件-devStyle,将你的eclipse变成idea风格
    springboot项目搭建:结构和入门程序
    POJ 3169 Layout 差分约束系统
    POJ 3723 Conscription 最小生成树
    POJ 3255 Roadblocks 次短路
    UVA 11367 Full Tank? 最短路
    UVA 10269 Adventure of Super Mario 最短路
    UVA 10603 Fill 最短路
    POJ 2431 Expedition 优先队列
  • 原文地址:https://www.cnblogs.com/windinsky/p/1390071.html
Copyright © 2020-2023  润新知