首页 > 代码库 > 参数传递

参数传递

参数传递

当调用带有参数的方法时,您需要向方法传递参数。

  • 值传递参数:这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。
using System;

namespace CodeReview
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 0;
            int b = 1;
            Console.WriteLine("在交换之前,a 的值: {0}", a);
            Console.WriteLine("在交换之前,b 的值: {0}", b);
            Exchange(a, b);
            Console.WriteLine("在交换之前,a 的值: {0}", a);
            Console.WriteLine("在交换之前,b 的值: {0}", b);
            //即使在函数内改变了值,值也没有发生任何的变化。
            Console.ReadKey();
        }
        static void Exchange(int x, int y)
        {
            int temp;
            temp = x;
            x = y;
            y = temp;
        }
    }
}
  • 引用传递参数:这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值(ref/out)
using System;

namespace CodeReview
{
    class Program
    {
        /// <summary>
        /// ref 关键字使参数按引用传递.其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中  若要使用 ref 参数,方法定义和调用方法都必须显式使用 ref 关键字。
        /// out 关键字会导致参数通过引用来传递.这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化    若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            int[] arr = { 1, 2, 3, 5, 67, 7 };
            float r_avg = 0;
            int r_max = 0;
            int r_min = 0;
            int r_sum = GetIntResultRef(arr, ref r_avg, ref r_max, ref r_min);//ref参数使用之前必须初始化
            Console.WriteLine("Ref:Sum:{0},Max:{1},Min:{2},Avg:{3}", r_sum, r_max, r_min, r_avg);
            float o_avg;//out参数不需要初始化
            int o_max;
            int o_min;
            int o_sum = GetIntResultOut(arr, out o_avg, out o_max, out o_min);//out参数使用之前必须初始化
            Console.WriteLine("Out:Sum:{0},Max:{1},Min:{2},Avg:{3}", o_sum, o_max, o_min, o_avg);
            Console.ReadKey();
        }
        /// <summary>
        /// 案例:定义一个方法,求一个整数数组中的总和/最大值/最小值/平均数.如果是一个方法只能有一个返回值,那只能每一个都得定义一个方法来实现,不过有了ref和out这实现起来就方便多了。
        /// </summary>
        /// <returns></returns>
        static int GetIntResultRef(int[] arr, ref float avg, ref int max, ref int min)
        {
            int sum = 0;
            max = arr[0];
            min = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
                sum += arr[i];
                if (max < arr[i])
                {
                    max = arr[i];
                }
                if (min > arr[i])
                {
                    min = arr[i];
                }
            }
            avg = sum / arr.Length;
            return sum;
        }
        static int GetIntResultOut(int[] arr, out float avg, out int max, out int min)
        {
            int sum = 0;
            max = arr[0];
            min = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
                sum += arr[i];
                if (max < arr[i])
                {
                    max = arr[i];
                }
                if (min > arr[i])
                {
                    min = arr[i];
                }
            }
            avg = sum / arr.Length;
            return sum;
        }
    }
}

C#中除非显式指定,否则:所有值类型默认都通过值来传递,所有引用类型都通过引用传递

ref和out都是用来显式将值类型通过引用传递的关键字

using System;namespace CodeReview
{
    /// <summary>
    /// C#中除非显式指定,否则:所有值类型默认都通过值来传递,所有引用类型都通过引用传递
    /// ref和out都是用来显式将值类型通过引用传递的关键字
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("***********值类型参数***********");
            Console.WriteLine("****初始化****");
            int i = 1;//int是值类型,按值传递
            Console.WriteLine(i);
            UpdateInt(i);
            Console.WriteLine("****更新后****");
            Console.WriteLine(i);

            Console.WriteLine("***********引用类型参数***********");
            Console.WriteLine("****初始化****");
            string[] srr = { "1", "2" };//数组是引用类型,按引用传递
            foreach (var s in srr)
            {
                Console.WriteLine(s);
            }
            UpdateArrFirst(srr);
            Console.WriteLine("****更新后****");
            foreach (var s in srr)
            {
                Console.WriteLine(s);
            }

            string str = "1";//string字符串传递(字符串是不可变的,改变一个字符串的值就会创建一个新的字符串)
            Console.WriteLine("string字符串原始值:{0}", str);
            UpdateString(str);
            Console.WriteLine("string字符串修改后的值:{0}", str);
            Console.ReadKey();
        }
        static void UpdateInt(int i)
        {
            i += 10;
        }
        static void UpdateArrFirst(string[] arr)
        {
            arr[0] = "4";
        }
        static void UpdateString(string str)
        {
            str = str + "Two";
        }
    }
}

命名参数:参数一般需要按定义的顺序传递给方法,命名参数允许按任意顺序传递。

using System;

namespace CodeReview
{
    class Program
    {
        static void Main(string[] args)
        {
            string name = JoinString("", "");//按顺序传递
            Console.WriteLine(name);
            name = JoinString(b: "", a: "");//任意顺序传递
            Console.WriteLine(name);
            Console.ReadKey();
        }
        static string JoinString(string a, string b)
        {
            return a + b;
        }
    }
}

 

可选参数:参数可以是可选的,但是必须为可选参数提供默认值,可选参数必须定义在方法所有参数最后的位置

using System;

namespace CodeReview
{
    class Program
    {
        static void Main(string[] args)
        {
            string name = JoinString("", "", "bay");//按顺序传递
            Console.WriteLine(name);
            Console.ReadKey();
        }
        static string JoinString(string a, string b, string c = "hello")
        {
            return a + b + c;//其中c为可选参数,如果不传递值就使用默认值
        }
    }
}

 

 

 总结:

ref和out的区别在C# 中,既可以通过值也可以通过引用传递参数。通过引用传递参数允许函数成员更改参数的值,并保持该更改。若要通过引用传递参数, 可使用ref或out关键字。ref和out这两个关键字都能够提供相似的功效,其作用也很像C中的指针变量。它们的区别是:

1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。

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

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

4、字符串是不可变的,修改一个字符串的值就会创建一个新的字符串。

参数传递