除了按值和引用,方法參數(shù)的第三種傳遞方式
參數(shù)在方法種具有按“值(by value)”和“引用(by ref)”兩種傳遞方式,這是每個.NET程序員深入骨髓得基本概念。但是我若告訴你,.NET規(guī)定的參數(shù)傳遞形式其實是三種,會不會顛覆你的認(rèn)知。
一、官方描述
二、TypedReference結(jié)構(gòu)體
三、三個特殊的方法
四、三種參數(shù)傳遞方式
一、官方描述
三種參數(shù)傳遞方式并非我們杜撰出來的,而是寫在.NET最核心的規(guī)范文檔ECMA-355中(I.12.4.1.5),原文如下:
The CLI supports three kinds of parameter passing, all indicated in metadata as part of the signature of the method. Each parameter to a method has its own passing convention (e.g., the first parameter can be passed by-value while all others are passed byref). Parameters shall be passed in one of the following ways (see detailed descriptions below):
- By-value – where the value of an object is passed from the caller to the callee.
- By-reference – where the address of the data is passed from the caller to the callee, and the type of the parameter is therefore a managed or unmanaged pointer.
- Typed reference – where a runtime representation of the data type is passed along with the address of the data, and the type of the parameter is therefore one specially supplied for this purpose.
It is the responsibility of the CIL generator to follow these conventions. Verification checks that the types of parameters match the types of values passed, but is otherwise unaware of the details of the calling convention.
三種參數(shù)傳遞方式如下:
- By-value:傳遞參數(shù)的值。這里所謂的值分兩種情況,對于值類型,變量的值就是承載目標(biāo)值的字節(jié),比如參數(shù)類型是一個我們自定義的結(jié)構(gòu)體,那么傳遞的是承載這個結(jié)構(gòu)體內(nèi)容的所有字節(jié);對于引用類型,變量的值是目標(biāo)對象的內(nèi)存地址,所以傳遞的這個地址(4/8字節(jié));
- By-Reference: 傳遞的是變量所在的位置(Location),可能是變量在堆棧上的內(nèi)存地址,或者數(shù)組元素在堆上的內(nèi)存地址。所以方法不僅僅可以從這個地址讀取原始參數(shù)當(dāng)前的值,還可以通過填充字節(jié)到此位置改變原始的值。對于值類型,被調(diào)用方法可以將原始的值“就地”變成一個新的值;對于引用類型,方法則會原來的引用指向一個新的對象。
- Typed reference:可以認(rèn)為強類型的引用,在By-Reference基礎(chǔ)上還傳遞參數(shù)的類型;
二、TypedReference
基于Typed reference的傳遞時通過如果這個TypedReference結(jié)構(gòu)體實現(xiàn)的,從其定義可以看出它通過字段_value保持值得引用,并利用_type確定其類型。它定義了一系列靜態(tài)方法完成一些基于TypedReference得基本操作,比如創(chuàng)建一個TypedReference對象,將一個TypedReference對象轉(zhuǎn)換成Object,獲取TypedReference對象得目標(biāo)類型等。值得一提的是,這個類型不是CLS兼容的([CLSCompliant(false)]),這限制了該類型的使用范圍,所以TypedReference并不是一個會經(jīng)常使用的類型。
[NullableContext(2)] [Nullable(0)] [IsByRefLike] [NonVersionable] [CLSCompliant(false)] public struct TypedReference { private readonly ref byte _value; private readonly IntPtr _type; public unsafe static object ToObject(TypedReference value); public unsafe static TypedReference MakeTypedReference(object target, FieldInfo[] flds); public static Type GetTargetType(TypedReference value); public static RuntimeTypeHandle TargetTypeToken(TypedReference value); public static void SetTypedReference(TypedReference target, object value); }
三、三個特殊的方法
TypedReference還涉及三個如下三個特殊方法或者函數(shù),可能很多開源人員都沒有見過:
- __makeref:創(chuàng)建一個新的TypedReference對象;
- __reftype:獲取引用的目標(biāo)類型;
- __refvalue:獲取和設(shè)置引用的值;
四、三種參數(shù)傳遞方式
我們通過如下這個簡單的例子來演示上述的三種參數(shù)傳遞方式,它們分別體現(xiàn)在三個對應(yīng)的方法上。模擬按照Typed reference進行參數(shù)傳遞的PassByTypedReference方法將參數(shù)類型定義為TypedReference,它通過斷言檢驗傳遞參數(shù)的類型(通過調(diào)用__reftype方法獲取),并通過調(diào)用__refvalue修改參數(shù)的值。
PassByValue(value); Debug.Assert(value == int.MinValue); PassByReference(ref value); Debug.Assert(value == int.MaxValue); value = int.MinValue; PassByTypedReference(__makeref(value)); Debug.Assert(value == int.MaxValue); static void PassByValue(int v) => v = int.MaxValue; static void PassByReference(ref int v) => v = int.MaxValue; static void PassByTypedReference(TypedReference v) { Debug.Assert(__reftype(v) == typeof(int)); __refvalue(v, int) = int.MaxValue; }


參數(shù)在方法種具有按“值(by value)”和“引用(by ref)”兩種傳遞方式,這是每個.NET程序員深入骨髓得基本概念。但是我若告訴你,.NET規(guī)定的參數(shù)傳遞形式其實是三種,會不會顛覆你的認(rèn)知。
浙公網(wǎng)安備 33010602011771號