研究Int32&的時候,無意中發現C#裡面還有4個Undocument Keyword, 分別是__makeref, __reftype, __refvalue 以及__arglist。 其中前三個keyword可以這樣用:
int i = 1;
TypedReference tr = __makeref(i);
Type t = __reftype(tr); //t = System.Int32
int i1 = __refvalue(tr, int); //i1 = 1
int i2 = (int)TypedReference.ToObject(tr); //i2 = 1
i++; //i = 2
int i3 = __refvalue(tr, int); //i3 = 2
(關於TypedReference類型MSDN是這樣描述的:Describes objects that contain both a managed pointer to a location and a runtime representation of the type that may be stored at that location. 同時TypedReference有
[CLSCompliant(false)]標記)
於是我們可以用下面這種方法來類比ByRef的參數
public class MyClass
{
public static void Main()
{
int v = 99;
TypedReference trParameters = __makeref(v);
Foo(trParameters);
Console.WriteLine("v = {0}", v); // v = 100
}
public static void Foo(TypedReference tr)
{
if(__reftype(tr) == typeof(int))
{
__refvalue(tr, int)++;
}
}
}
比較不爽的就是我們必須在Foo方法體中判斷TypedReference包含的類型。
注意如果把Foo寫成public static void Foo(ref TypedReference tr),編譯器會抱怨說:Method or delegate parameter cannot be of type 'ref System.TypedReference'。
至於__arglist則可以類比params關鍵字,抄個例子:
public void Function(__arglist)
{
ArgIterator iterator = new ArgIterator(__arglist);
for (int count=iterator.GetRemainingCount(); count>0; count--)
{
TypedReference typedRef = iterator.GetNextArg();
Console.WriteLine(__refvalue(typedRef, int));
}
}
調用它:Function(__arglist(2,3,4)); 輸出2,3,4
後註:這4個keyword畢竟是undocument的,微軟也沒有提供任何支援,所以不排除以後被delete掉。Mono下面的編譯器似乎也不支援,不過我在vs2005 beta裡面實驗還是有效。
Updated: Flier Lu在他的blog對__arglist的使用作了更深入的探討,推薦閱讀。 :)