昨天寫了個關(guān)于socket接收udp包的程序,調(diào)用了socket.ReceiveFrom方法,發(fā)現(xiàn)了一個c#中關(guān)于ref和out參數(shù)傳遞時的問題,這里提出來和大家共同探討一下,首先聲明,下面的結(jié)論都是本人推測,還沒有得到任何定論,若有錯誤請大家指正。
首先,ReceiveFrom方法的原型為
public int ReceiveFrom(byte[], ref EndPoint);
有一個為ref的EndPoint參數(shù),用它來返回收到包的源地址信息,ref的語義是傳引用,即對所傳引用的修改可以反映到方法外面。我一般都使用IPEndPoint來表示地址信息,所以很自然的使用了如下的調(diào)用方法
(代碼1)
IPEndPoint iep = new IPEndPoint(IPAddress.Any,0);
socket.ReceiveFrom(buffer,ref (EndPoint)iep);
這時編譯時出現(xiàn)了一下的錯誤,“ref或out參數(shù)必須是一個lvalue”,iep怎么會不是一個左值呢?關(guān)鍵是在調(diào)用方法時使用的強制轉(zhuǎn)換(例如(EndPoint)iep),我改了一下代碼
(代碼2)
IPEndPoint iep = new IPEndPoint(IPAddress.Any,0);
EndPoint ep = (EndPoint)iep;
socket.ReceiveFrom(buffer,ref (EndPoint)iep);
這次通過編譯了。為什么在方法調(diào)用時會出問題?這里要考慮類型強制轉(zhuǎn)換時的一個細節(jié),強制轉(zhuǎn)換時編譯器會先生成一個臨時引用,然后再把這個臨時引用傳給一個和轉(zhuǎn)換類型相同的引用,這個臨時引用比較特別——不是一個左值(lvalue),不能被賦值!而使用ref參數(shù)的方法一般都要對這個引用做修改,如果直接把這個臨時引用傳進去當(dāng)時編譯器會抱怨ref或out參數(shù)必須是一個lvalue。而代碼2首先將這個臨時引用賦值到一個常規(guī)引用上去,這時這個常規(guī)引用便是可以復(fù)制的了。