zoukankan      html  css  js  c++  java
  • (C#)方法参数关键字:ref、out、params详解

    C#)方法参数关键字:refoutparams详解

    备注:以下来自MSDN和网络参考,经过整理后的文档

    refC# 参考)

    ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。例如:

    class RefExample

    {

        static void Method(ref int i)

        {

            i = 44;

        }

        static void Main()

        {

            int val = 0; //使用ref val必须先初始化

            Method(ref val);

            // val is now 44

        }

    }

    Ø 传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。

    尽管 ref out 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:

    class CS0663_Example

    {

        // Compiler error CS0663: "cannot define overloaded

        // methods that differ only on ref and out".

        public void SampleMethod(ref int i) { }

        public void SampleMethod(out int i) { }

    }

    但是,如果一个方法采用 ref out 参数,而另一个方法不采用这两个参数,则可以进行重载,如下例所示:

    class RefOutOverloadExample

    {

        public void SampleMethod(int i) { }

        public void SampleMethod(ref int i) { }

    }

    Ø 属性不是变量,因此不能作为 ref 参数传递。

    按引用传递值类型(如本主题前面所示)是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。下面的示例显示出当引用类型作为 ref 参数传递时,可以更改对象本身。

    class RefRefExample

    {

        static void Method(ref string s)

        {

            s = "changed";

        }

        static void Main()

        {

            string str = "original";

            Method(ref str);

            // str is now "changed"

        }

    }

    outC# 参考)

    out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。例如:

    class OutExample

    {

        static void Method(out int i)

        {

            i = 44;

        }

        static void Main()

        {

            int value; //使用out ,value不必初始化

            Method(out value);

            // value is now 44

        }

    }

    Ø 属性不是变量,因此不能作为 out 参数传递。

     

    当希望方法返回多个值时,声明 out 方法很有用。使用 out 参数的方法仍然可以将变量作为返回类型来访问(请参见 return),但它还可以将一个或多个对象作为 out 参数返回给调用方法。此示例使用 out 在一个方法调用中返回三个变量。请注意,第三个参数所赋的值为 Null。这样使方法可以有选择地返回值。

    class OutReturnExample

    {

        static void Method(out int i, out string s1, out string s2)

        {

            i = 44;

            s1 = "I've been returned";

            s2 = null;

        }

        static void Main()

        {

            int value;

            string str1, str2;

            Method(out value, out str1, out str2);

            // value is now 44

            // str1 is now "I've been returned"

            // str2 is (still) null;

        }

    }

    paramsC# 参考)

    params 关键字可以指定在参数数目可变处采用参数的方法参数。

     

    Ø 在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。

     

    // cs_params.cs

    using System;

    public class MyClass

    {

        public static void UseParams(params int[] list)

        {

            for (int i = 0 ; i < list.Length; i++)

            {

                Console.WriteLine(list[i]);

            }

            Console.WriteLine();

        }

        public static void UseParams2(params object[] list)

        {

            for (int i = 0 ; i < list.Length; i++)

            {

                Console.WriteLine(list[i]);

            }

            Console.WriteLine();

        }

        static void Main()

        {

            UseParams(1, 2, 3);

            UseParams2(1, 'a', "test");

            // An array of objects can also be passed, as long as

            // the array type matches the method being called.

            int[] myarray = new int[3] {10,11,12};

            UseParams(myarray);

        }

    }

    输出:

    1

    2

    3

    1

    a

    test

    10

    11

    12

    使用 ref out 传递数组(C# 编程指南)

    与所有的 out 参数一样,在使用数组类型的 out 参数前必须先为其赋值,即必须由被调用方为其赋值。例如:

    static void TestMethod1(out int[] arr)

    {

        arr = new int[10];   // definite assignment of arr

    }

    与所有的 ref 参数一样,数组类型的 ref 参数必须由调用方明确赋值。因此不需要由接受方明确赋值。可以将数组类型的 ref 参数更改为调用的结果。例如,可以为数组赋以 null 值,或将其初始化为另一个数组。例如:

    static void TestMethod2(ref int[] arr)

    {

        arr = new int[10];   // arr initialized to a different array

    }

    下面的两个示例说明 out ref 在将数组传递给方法时的用法差异。

    示例 1

    在此例中,在调用方(Main 方法)中声明数组 theArray,并在 FillArray 方法中初始化此数组。然后将数组元素返回调用方并显示。

    class TestOut

    {

        static void FillArray(out int[] arr)

        {

            // Initialize the array:

            arr = new int[5] { 1, 2, 3, 4, 5 };

        }

        static void Main()

        {

            int[] theArray; // Initialization is not required

            // Pass the array to the callee using out:

            FillArray(out theArray);

            // Display the array elements:

            System.Console.WriteLine("Array elements are:");

            for (int i = 0; i < theArray.Length; i++)

            {

                System.Console.Write(theArray[i] + " ");

            }

        }

    }

    输出 1

    Array elements are:

    1 2 3 4 5

    示例 2

    在此例中,在调用方(Main 方法)中初始化数组 theArray,并通过使用 ref 参数将其传递给 FillArray 方法。在 FillArray 方法中更新某些数组元素。然后将数组元素返回调用方并显示。

    class TestRef

    {

        static void FillArray(ref int[] arr)

        {

            // Create the array on demand:

            if (arr == null)

            {

                arr = new int[10];

            }

            // Fill the array:

            arr[0] = 1111;

            arr[4] = 5555;

        }

        static void Main()

        {

            // Initialize the array:

            int[] theArray = { 1, 2, 3, 4, 5 };

            // Pass the array using ref:

            FillArray(ref theArray);

            // Display the updated array:

            System.Console.WriteLine("Array elements are:");

            for (int i = 0; i < theArray.Length; i++)

            {

                System.Console.Write(theArray[i] + " ");

            }

        }

    }

    输出 2

    Array elements are:

    1111 2 3 4 5555

    refout的区别:

    通常我们向方法中传递的是值.方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不将受到影响.此外我们还有其他向方法传递参数的形式,引用(ref)和输出(out).
        
        
    有时,我们需要改变原来变量中的值,这时,我们可以向方法传递变量的引用,而不是变量的值.引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值.变量的值存储内存,可以创建一个引用,他指向变量在内存中的位置.当引用被修改时,修改的是内存中的值,因此变量的值可以将被修改.当我们调用一个含有引用参数的方法时,方法中的参数将指向被传递给方法的相应变量,因此,我们会明白,为什么当修改参数变量的修改也将导致原来变量的值.

     

     我们发现,refout似乎可以实现相同的功能.因为都可以改变传递到方法中的变量的值.但是,二者本质本质的区别就是,ref是有进有出,out是只出不进.在含有out关键字的方法中,变量必须由方法参数中不含out(可以是ref)的变量赋值或者由全局(即方法可以使用的该方法外部变量)变量赋值,out的宗旨是保证每一个传出变量都必须被赋值.

     

    ref和out的比较:

    1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化,因为out的函数会清空变量,即使变量已经赋值也不行,退出函数时所有out引用的变量都要赋值,ref引用的可以修改,也可以不修改。

    2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。

    3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。  

     

      区别可以参看下面的代码:

    using System;

    class TestApp

    {

     static void outTest(out int x, out int y)

     {//离开这个函数前,必须对x和y赋值,否则会报错。

      //y = x;

      //上面这行会报错,因为使用了out后,x和y都清空了,需要重新赋值,即使调用函数前赋过值也不行

      x = 1;

      y = 2;

     }

     static void refTest(ref int x, ref int y)

     {

      x = 1;

      y = x;

     }

     public static void Main()

     {

      //out test

      int a,b;

      //out使用前,变量可以不赋值

      outTest(out a, out b);

      Console.WriteLine("a={0};b={1}",a,b);

      int c=11,d=22;

      outTest(out c, out d);

      Console.WriteLine("c={0};d={1}",c,d);

     

      //ref test

      int m,n;

      //refTest(ref m, ref n);

      //上面这行会出错,ref使用前,变量必须赋值

     

      int o=11,p=22;

      refTest(ref o, ref p);

      Console.WriteLine("o={0};p={1}",o,p);

     }

    }

     

    注:在C#中,方法的参数传递有四种类型:

    1、         传值(by value)

    2、         传址(by reference)

    3、         输出参数(by output)

    4、         数组参数(by array)。

    传值参数无需额外的修饰符,传址参数需要修饰符ref,输出参数需要修饰符out,数组参数需要修饰符params。

    传值参数在方法调用过程中如果改变了参数的值,那么传入方法的参数在方法调用完成以后并不因此而改变,而是保留原来传入时的值。

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

     

    方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。

     

    若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。

  • 相关阅读:
    ubuntu服务器全部署
    果蝇优化算法(FOA)
    小波神经网络(WNN)
    R语言预测实战(第二章--预测方法论)
    ARIMA模型--粒子群优化算法(PSO)和遗传算法(GA)
    R语言预测实战(第一章)
    卷积神经网络(CNN)
    RSS(简易信息聚合)和jieba(第三方分词组件)
    第四章--基于概率论的分类方法:朴素贝叶斯--新闻分类(三)
    第四章--基于概率论的分类方法:朴素贝叶斯--过滤垃圾邮件(二)
  • 原文地址:https://www.cnblogs.com/stalwart/p/1913435.html
Copyright © 2011-2022 走看看