天天看點

參數ref與out

  通常我們向方法中傳遞的是值,方法獲得的是這些值的一個拷貝,然後使用這些拷貝,當方法運作完畢後,這些拷貝将被丢棄,而原來的值不會受到影響。 這種情況是通常的,當然還有另外一種情況,我們向方法傳遞參數的形式,引用(ref)和輸出(out)。

  有時,我們需要改變原來變量中的值,這是我們可以向方法傳遞變量引用,而不是變量的值,引用是一個變量,他可以通路原來變量的值,修改引用将修改原來變量的值。變量的值存儲在記憶體中,可以建立一個引用,他指向變量在記憶體中的位置,當引用被修改時,修改的是記憶體中的值,是以變量的值可以被修改,當我們調用一個含有引用參數的方法時,方法中的參數将指向被傳遞給方法的相應變量,是以,我們會明白為什麼當修改參數變量的修改也将導緻原來變量的值被修改。

ref

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleAppTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Gump gump = new Gump();
            List<int> list = new List<int>();
            double a = 3;
            gump.AddInt(1,ref list);
            gump.AddInt(2, ref list);
            gump.AddInt(3, ref list);
            Console.WriteLine($"a={a}");
            Console.WriteLine(string.Join(",", list.Select(x => x.ToString())));
            Console.ReadLine();
        }
    }

    class Gump
    {
        public double Square(ref double x)
        {
            x = x * x;
            return x;
        }

        public void AddInt(int i, ref List<int> list)
        {
            list.Add(i);
        }
    }
}      

out

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleAppTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Gump doit = new Gump();
            double x1 = 10;
            double cubed1 = 0;
            double squared1 = 0;
            double half1 = 0;
            doit.math_routines(x1, out half1, out squared1, out cubed1);
            Console.WriteLine("Before method->x1={0}", x1);
            Console.WriteLine("Before method->half1={0}", half1);
            Console.WriteLine("Before method->squared1={0}", squared1);
            Console.WriteLine("Before method->cubed1={0}", cubed1);
            doit.math_routines(x1, out half1, out squared1, out cubed1);
            Console.WriteLine("After method->x1={0}", x1);
            Console.WriteLine("After method->half1={0}", half1);
            Console.WriteLine("After method->squared1={0}", squared1);
            Console.WriteLine("After method->cubed1={0}", cubed1);
            Console.ReadLine();
        }
    }

    class Gump
    {
        public void math_routines(double x, out double half, out double squared, out double cubed)
        //可以是:public void math_rotines(//ref double x,out double half,out double squared,out double cubed)
        //但是,不可以這樣:public void math_routines(out double x,out double half,out double squared,out double cubed)
        //對本例子來說,因為輸出的值要靠X指派,是以X不能再為輸出值
        {
            half = x / 2;
            squared = x * x;
            cubed = x * x * x;

        }

        public void AddInt(int i, out List<int> list1, out List<int> list2)
        {
            //引用類型 out 要先執行個體化
            list1 = new List<int>();
            list2 = new List<int>();
            if (i % 2 == 1)
            {
                list1.Add(1);
            }
        }
    }
}      

通過制定傳回類型,可以從方法傳回一個值,有時候,需要傳回多個值,雖然我們可以使用ref來完成,但是C#專門提供了一個屬性類型,關鍵字為out,介紹完後,我們将說明ref和out的差別。

我們發現,ref和out似乎可以實作相同的功能,因為都可以改變傳遞到方法中的變量的值,但是二者本質的差別就是,ref是傳入值,out是傳出值,在含有out關鍵之的方法中,變量 必須有方法參數中不含out(可以是ref)的變量指派或者由全局(即方法可以使用的該方法外部變量)變量指派,out的宗旨是保證每一個傳出變量都必須被指派

在傳入變量的時候,out關鍵字的變量可以不被初始化,但是沒有out 關鍵字的值要被指派。而ref參數在傳遞給方法是,就已經被指派了,是以ref側重修改,out側重輸出。