1. 程式人生 > >利用反射呼叫方法時,處理ref,out引數需要注意的問題

利用反射呼叫方法時,處理ref,out引數需要注意的問題

專案中如下的泛型方法,因為要在執行時,動態指定型別引數,所以要利用反射來實現。

public static TR Deserialize<TR>(byte[] source, ref int offset)

一般做法如下:

// 變數 type是該方法所在型別的執行時Type
// model是已經定義的例項
MethodInfo genericMethod = type.GetMethod("Deserialize", BindingFlags.Public | BindingFlags.Static);
MethodInfo mi = genericMethod.MakeGenericMethod(model.GetType());

反射拿到MethodInfo之後,即可呼叫方法

// int p
// byte[] source
// object result
result = mi.Invoke(null, new object[]{source, p});

注意這裡的呼叫方法傳的引數,形參offset並沒有像直接呼叫方法那樣指定ref修飾符,像refout這樣的引數修飾符在利用反射呼叫方法時是不需要指定的

回到我們的主題,我們希望方法呼叫之後,我們傳的引數p的值被修改了,事實上,我們會發現,引數p的值並未被改變。

MSDN上面,.net framework 4.5版本中,特別提到了這一點,refout引數可能被修改。那我們的問題出在哪裡了呢?

問題出在了我們傳引數的過程。上面的方法呼叫,引數被裝入陣列,由Invoke方法傳遞給mi指向的方法。我們構造object陣列的初始化過程,是值傳遞的。另一方面,這個object陣列在呼叫完成後,就被丟掉了。將上述程式碼改成如下寫法:

object[] args = new object[]{source, p};
result = mi.Invoke(null, args);
p = (int)args[1];

然後,我們就會發現,被修改的引數,其實在引數陣列中好好的放著呢。