【C#】ref與out // 傳值與傳址

傳值Call by Value / 傳址 Call by Reference

學過c++的一定會遇到
傳值與傳址
一開始聽到整個
wtf 這兩個是尛阿

到最近看了一下ref跟out之後才真的了解
======

一般資料型別分為兩種
一個是實質型別
一個是參考型別

實質型別就是 int float char...等基礎的型別
而他變數記憶體存放的"內容"是值 所以稱為實"值"型別
也就是"傳值",當你在使用他的時候
他們之間傳遞的方式都是把值copy一份後再傳進去
像是以下
一開始宣告
int A=5, B=10;
並且設一個方法
void ChangeValue(int a,int b)
{
    a = 1;
    b = 2;
}

之後在Start()方法內調用
Debug.Log(" A  :" + A + " b :" + B);
 ChangeValue(A, B);
 Debug.Log(" A  :" + A + " b :" + B);
分別是將AB傳進去前跟傳進去後





可以看到傳進去後值都沒改變,這是因為使用的方式只是傳值(call by value)而已
意思就是把"值"複製給對方,而複製完改變的東西並不會影響到本身的值,因此不會做任何改變

而下面可以對照看看
 Car car11 = new Car("car11");
 Car car22 = new Car("car22");

    void ChangeNewCarValue(Car _car11, Car _car22)
    {
        _car11._carName = "ChangeCAR11";
        _car22._carName = "ChangeCAR22";

    }

同樣的宣告 同樣的方法 同樣在Start內打上
Debug.Log(" car11 :" + car11._carName + " car22 :" + car22._carName);
ChangeNewCarValue(car11, car22);
Debug.Log(" car11 :" + car11._carName + " car22 :" + car22._carName);
出來的結果則為






結果卻改變了,因此從上可以推論出來Car是一個傳址Call by Reference
意思就是,它傳遞的不是複製一份出來的值,而是傳遞丟入物件的記憶體位址
然後間接透過它來操作物件,跟指標很類似。

其實在C/C++的時候 正確是有三個名詞的
call by value 傳值、call by reference 傳參考、call by address傳址
但由於這裡要講的是C#,所以用官方的翻譯來敘述 ->詳細點我
如果要詳細了解這三個有什麼差別 可以再去google

ref、out

ref 關鍵字
會導致引數由參考加以傳遞,而非透過值。
參考程式碼 :
class RefExample
    {
        static void Method(ref int i)
        {
            // Rest the mouse pointer over i to verify that it is an int.
            // The following statement would cause a compiler error if i
            // were boxed as an object.
            i = i + 44;
        }

        static void Main()
        {
            int val = 1;
            Method(ref val);
            Console.WriteLine(val);

            // Output: 45
        }
    }


可以發現實質類型使用ref關鍵字之後,就會變得像是上面參考類型一樣
可以修改傳入的參數了
class RefExample
    {
        static void Method(ref int i)
        {
            // Rest the mouse pointer over i to verify that it is an int.
            // The following statement would cause a compiler error if i
            // were boxed as an object.
            i = i + 44;
        }

        static void Main()
        {
            int val = 1;
            Method(ref val);
            Console.WriteLine(val);

            // Output: 45
        }
    }

那問題來了,參考類型本身傳遞就可以直接修改值了
為何還會使用ref關鍵字加到參考型別身上呢?
1.明確提示
加了之後 不管給別人用還是自己用 都可以知道 傳入的參數是會被改變值得
不管傳入實質或參考都一樣
2.string的不變性
參考這裡
3. 為了修改默認值類型

ref重點:(msdn)
1.傳遞至 ref 參數的引數,在傳遞之前必須先初始化。
2.不能將ref和out用於async修飾詞定義的非同步方法。
3.有進有出

out關鍵字

基本上跟ref一樣
想要多個回傳值的時候,可以使用out

    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;
        }
    }


ref跟out在使用上有很微小的差距

使用out的話,他不需要在被調用前初始化
但是調用者需要在返回之前指定輸出的參數

另一方面,可以用這樣去想
out類似於將方法附加返回值,也就是回傳多個值啦



Share:
Read More

【C#】特性

特性是什麼

簡單來說 
Unity最常看到的就是在屬性或字段前面加上
[Serializefield] private int Something = 5; 
而前面這個框框內的就是特性
它的功用就是賦予後面那一串陳述某種技能
像上面那個,就是Unity內的特性 
一般我們要在外面的editor調整數值,要將字段的層級調為pubic
但是有時候又不能讓他在其他腳本調用的時候被看見
這時候就可以用到它了→[Serializefield]  (點擊可看文件)
可以強制將私有字段設為在編輯器上可見






看起來就會變成這樣

然後還有,unity在更新它的api的時候 舊方法常常會被新方法取代
但一下把它移除,用戶難免會覺得很莫名 「常用的東西不見的 你在跟我開玩笑嘛!!」的感覺
於是他就使用了Obsolete這個特性,這個特性主要就是【宣告過期功能】
恩 , 超簡略 ,看起來就是這樣




其他還有很多各種不同的特性
這裡只是先簡短介紹一下 其他就慢慢去查唄
Share:
Read More