.net框架读书笔记---引用参数(ref/out)
接上一篇.net框架讀書筆記---方法(類型造器)
默認情況下,CLR假設所有的方法參數都是按值傳遞參數的。當參數為引用類型的對象時,參數的傳遞是通過傳遞對象的引用(或)指針來完成的。這意味著方法可以改變引用對象,并且調用代碼可以看到這種改變的結果。
對于值類型實例的參數來說,傳遞給方法的將是值類型實例的一個拷貝。這意味著方法會得到一份屬于它自己的值類型實例的成員。而調用方法的代碼中的實例不會受到影響。
除了按值傳遞參數外,CLR還允許我們按引用的方式來傳遞參數.在C#中可以使用out和ref關鍵字來做到這一點。out和ref的區別是:
- ?一個方法的參數被標識為out,那么調用代碼在調用該方法之前可以不初始化該參數,并且調用方法不能直接讀取參數的值,它必須在返回之前為該參數賦值。
- 一個方法的參數被表示為ref,那么調用代碼在調用該方法前必須首先初始化該參數。被調用方法可以任意讀取該參數、或者為該參數賦值。
out關鍵字示例:
代碼 class Program{
static void Main(string[] args)
{
int x;//x不必初始化
SetVal(out x);
Console.WriteLine(x);//顯示為10
}
static void SetVal(out int v)
{
// int x = v;//該行代碼會報錯
v = 10;//SetVal方法必須初始化v;
}
}
?
上面代碼中,x首先被聲明在線程堆棧上。接著,x的地址被傳遞給SetVal。SetVal的參數v是一個指向int值類型的指針。在SetVal內部,v指向的int被賦值為10.當SetVal返回后,Main中的x的值為10,在值類型參數上使用out會提高代碼的效率,因為它避免l哦值類型的字段在方法調用時的拷貝操作。
ref關鍵字示例:
代碼 class Program{
static void Main(string[] args)
{
int x=5;//x必須初始化
AddVal(ref x);
Console.WriteLine(x);//顯示為15
}
static void AddVal(ref int v)
{
int x = v;//addVal方法可以直接使用經過初始化的v而不報錯
v += 10;
}
}
?
上面代碼中,x首先被聲明在線程堆棧上,緊接著被初始化為5,隨后x的地址被傳遞給AddVal,AddVal的參數是一個指向int值類型的指針。在AddVal內部,v指向的必須是一個結果初始化的值,這樣AddVal才可以在任何表達式中使用該初始值。當AddVal返回后,Main中x的值將為15;
CLR允許根據out和ref參數來重載方法,下面代碼合法:
public class Point{
static void Add(Point p) { }
static void Add(ref Point p) { }
}
?
還有:
public class Point{
static void Add(Point p) { }
static void Add(out Point p)
{
p = new Point();//必須給out參數賦值
}
}
?
但是,僅僅通過out和ref來區分重載方法是不合法的,下面代碼編譯它不過:
public class Point{
static void Add(ref Point p) { }
static void Add(out Point p)
{
p = new Point();//必須給out參數賦值
}
}
?
因為經過jit編譯后打代碼是相同的。
在值類型參數上使用out和ref關鍵字與用傳值的方式來傳遞引用類型的參數在某種程度上具有相同的行為,前一種情況,out和ref關鍵字允許被調用方法直接操作一個值類型實例,調用代碼必須為該實例分配內存,被調用方法操作該內存。對于后一種情況,調用代碼為引用類型對象分配內存,而被調用方法通過傳入的引用(指針)來操作對象。看下面代碼:
代碼 class Program{
static void Main(string[] args)
{
FileStream fs;
//打開第一個文件
StartProcessingFiles(ref fs);
for (; fs != null; ContinueProcessingFiles(ref fs))
{
//處理文件
fs.Read();
}
}
static void StartProcessingFiles(ref FileStream fs)
{
fs = new FileStream();
}
static void ContinueProcessingFiles(ref FileStream fs)
{
fs.Close();//關閉上一次操作的文件
//打開下一個文件,沒有返回null
if (noFiles)
fs = null;
else
{
fs = new FileStream();
}
}
}
?
該代碼最大的不同在于有著out和ref修飾的引用類型參數的方法創建一個對象后,指向新對象的指針會返回到調用代碼。
下面代碼演示了使用ref來交換兩個引用:
static public void Swap(ref object a, ref object b){
object c = a;
a = b;
b = c;
}
?
CLR為了確保類型安全,按引用傳遞的變量必須和方法聲明的參數類型完全相同,如下面代碼將會報錯:
代碼 class Program{
static void Main(string[] args)
{
string s1 = "heaiping";
string s2 = "hap";
Swap(ref s1, ref s2);
}
static public void Swap(ref object a, ref object b)
{
object c = a;
a = b;
b = c;
}
}
?
因為object和string不匹配,要編譯同步代碼必須修改為:
代碼 class Program{
static void Main(string[] args)
{
string s1 = "heaiping";
string s2 = "hap";
Swap(ref s1, ref s2);
Console.WriteLine(s1);
Console.WriteLine(s2);
}
static public void Swap(ref string a, ref string b)
{
string c = a;
a = b;
b = c;
}
}
?
修正后編譯通過并得到期望值。
轉載于:https://www.cnblogs.com/sanjia/archive/2010/04/27/1722533.html
總結
以上是生活随笔為你收集整理的.net框架读书笔记---引用参数(ref/out)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VOA,with me
- 下一篇: 实用C#编程规范(转载)