參數修飾詞 in、out 和 ref 之間的差異
雖然對比於其他關鍵字,out 和 ref 關鍵字會較不熟悉,
不過還是來比較一下兩者的不同。
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string a;
testOut(out a);
string b = "ccc";
testRef(ref b);
Console.WriteLine("string a = {0}, string b = {1}", a, b);
int readonlyArgument = 44;
InArgExample(readonlyArgument);
Console.WriteLine(readonlyArgument); // value is still 44
Console.ReadKey();
}
static void testOut(out string i)
{
i = "ggg";
}
static void testRef(ref string i)
{
//can be do nothing
}
static void InArgExample(in int number)
{
// Uncomment the following line to see error CS8331
//number = 19;
}
}
}
1、在呼叫使用 ref 宣告輸入參數的方法時,呼叫端的輸入參數需先初始化;
反而使用 out 宣告輸入參數的方法,呼叫端的輸入參數不需要先初始化。
2、使用 ref 宣告輸入參數的方法時,輸入參數允許什麼事都不用做;
反而使用 out 宣告輸入參數的方法時,在方法回傳前輸入參數一定要被指派值。
3、編譯器在多載方法上,並不會把參數修飾詞視為不同的簽章 (signature),
也就是說,一種方法採用 ref 引數,而另一種方法採用 out 引數,
只要 ref、in、out 三者同時存在兩個,則不能多載方法。
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
public void SampleMethod(ref int i) { }
public void SampleMethod(out int i) { i = 1; }
public void SampleMethod(in int i) { }
}
4、必須在 C# 7.2 以上能使用 in 參數修飾詞,in 參數修飾詞是以傳址方式傳遞引數,
你可以先把 in 宣告的特性想成就是等於 ref 宣告,
但與 ref 宣告不同的是,經由 in 宣告的值是不能被修改的。
5、ref 與 out 在使用上,其 method argument 與 method parameter 前面都要明確指定,
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string a;
testOut(out a);
string b = "ccc";
testRef(ref b);
}
static void testOut(out string i) { i = "ggg"; }
static void testRef(ref string i) { }
}
}
而 in 在使用上則不須在 method argument 前面指定 in 參數修飾詞
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
InArgExample(44);
}
static void InArgExample(in int number) { }
}
}
6、在 C# 7.2,有加「in」參數修飾詞與沒有加修飾詞的方法,兩者可以多載,
當想要使用帶有「in」參數修飾詞的方法時,
只要在呼叫時也加上「in」參數修飾詞,就可區分開來。
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Show(3);
int readonlyArgument = 100;
Show(in readonlyArgument);
}
static void Show(int arg)
{
Console.WriteLine(arg);
}
static void Show(in int arg)
{
Console.WriteLine("in - " + arg);
}
}
}
執行結果為
7、out
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Call();
/*below the commented code,can not to be executed*/
//Console.WriteLine($"({x}, {y})");
Console.ReadKey();
}
static void Call()
{
GetCoordinates(out int x, out int y);
Console.WriteLine($"({x}, {y})");
}
static void GetCoordinates(out int a, out int b)
{
a = 100;
b = 200;
}
}
}
說明:
a、現在參數修飾詞「out」也可以在傳遞時再宣告,這可以減少程式碼的行數,增加可讀性。
b、這個變數在包含它本身的 { } 封閉區塊範圍內,所以接續宣告後面的程式碼可以直接使用這些變數。
c、如果你不在意某個 out 參數的傳回結果,可以使用 _ 代表忽略它:
static void Call()
{
GetCoordinates(out int x, out _);
Console.WriteLine($"({x})");
}
參考資料: