久久亚洲国产精品视频,中国AV片,最近中文字幕免费大全,国产亚洲精品久久久999功能介绍,欧美色女人

金融情報(bào)局網(wǎng)_中國金融門戶網(wǎng)站 讓金融財(cái)經(jīng)離的更近

實(shí)例方法和靜態(tài)方法有區(qū)別嗎? 世界微動(dòng)態(tài)


(資料圖片)

實(shí)例方法和靜態(tài)方法有區(qū)別嗎?對(duì)于很多人來說,這是一個(gè)愚蠢的問題。因?yàn)槲覀兌贾浪鼈兊膮^(qū)別,實(shí)例方法作用于某個(gè)具體的上下文對(duì)象,該上下文對(duì)象可以利用this關(guān)鍵字獲得;靜態(tài)方法則是定義在某個(gè)類型中,不存在上下文對(duì)象的概念。但是如果我們從函數(shù)的角度來看的話,不論是靜態(tài)方法還是實(shí)例方法都是一個(gè)用于處理輸入?yún)?shù)的操作,貌似又沒有什么區(qū)別。

以如下這個(gè)用于封裝一個(gè)整數(shù)的IntValue類型為例,它具有兩個(gè)AsInt32方法,實(shí)例方法返回當(dāng)前InValue對(duì)象的_value字段;靜態(tài)方法將IntValue對(duì)象作為參數(shù),返回該對(duì)象的_value字段。我們的問題是:這兩個(gè)AsInt32方法有分別嗎?

var target = new IntValue(123);target.AsInt32();IntValue.AsInt32(target);public class IntValue{    private readonly int _value;    public IntValue(int value) => _value = value;    public int AsInt32() => _value;    public static int AsInt32(IntValue value) => value._value;}

我們從IL的視角來看這兩個(gè)方法的聲明和實(shí)現(xiàn)。如下面的代碼片段所示,從方法聲明來看,實(shí)例方法AsInt32和靜態(tài)方法AsInt32確實(shí)不同,但是它們的實(shí)現(xiàn)卻完全一致。方法涉及三個(gè)IL指令:ldarg.0提取第1個(gè)參數(shù)壓入棧中,具體入棧的是指向IntValue對(duì)象的地址;目標(biāo)IntValue對(duì)象的_value字段通過ldfld指令被加載,最終通過ret指令作為結(jié)果返回。實(shí)例方法也好,靜態(tài)方法也罷,它們都被視為的普通函數(shù)。韓式只有輸入和輸出,并不存在所謂的上下文對(duì)象(this)。

.method public hidebysiginstanceint32 AsInt32 () cil managed{// Method begins at RVA 0x2178// Header size: 1// Code size: 7 (0x7).maxstack 8// return _value;IL_0000: ldarg.0IL_0001: ldfld int32 IntValue::_valueIL_0006: ret} // end of method IntValue::AsInt32
.method public hidebysig staticint32 AsInt32 (class IntValue "value") cil managed{.custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (01 00 01 00 00)// Method begins at RVA 0x2180// Header size: 1// Code size: 7 (0x7).maxstack 8// return value._value;IL_0000: ldarg.0IL_0001: ldfld int32 IntValue::_valueIL_0006: ret} // end of method IntValue::AsInt32

實(shí)例方法實(shí)際上將目標(biāo)對(duì)象作為它的第一個(gè)參數(shù),這與顯式將目標(biāo)對(duì)象作為第一個(gè)參數(shù)的靜態(tài)方法并沒有本質(zhì)的區(qū)別,所以調(diào)用它們的IL代碼也一樣。如下所示的就是上面C#針對(duì)這兩個(gè)方法的調(diào)用轉(zhuǎn)換生成的IL代碼。

.method private hidebysig staticvoid "
$" (string[] args) cil managed{// Method begins at RVA 0x213c// Header size: 12// Code size: 23 (0x17).maxstack 1.entrypoint.locals init ([0] class IntValue target)// IntValue intValue = new IntValue(123);IL_0000: ldc.i4.s 123IL_0002: newobj instance void IntValue::.ctor(int32)IL_0007: stloc.0// intValue.AsInt32();IL_0008: ldloc.0IL_0009: callvirt instance int32 IntValue::AsInt32()IL_000e: pop// IntValue.AsInt32(intValue);IL_000f: ldloc.0IL_0010: call int32 IntValue::AsInt32(class IntValue)IL_0015: pop// }IL_0016: ret} // end of method Program::"
$"

由于實(shí)例方法和靜態(tài)方法的“無差異性”,我們可以使用一些Hijack的方式“篡改”現(xiàn)有某個(gè)類型的實(shí)例方法。比如我們?cè)贗ntValue類型(可以定義任意類型中)中定義了一個(gè)總是返回int.MaxValue的AlwaysMaxValue方法。在演示程序中,我們通過調(diào)用Hijack方法將IntValue的實(shí)例方法AsInt32“替換”這個(gè)AlwaysMaxValue方法。

var target = new IntValue(123);Hijack(()=>target.AsInt32(), () => IntValue.AlwaysMaxValue(null!));Debug.Assert(target.AsInt32() == int.MaxValue);public class IntValue{    private readonly int _value;    public IntValue(int value) => _value = value;    public int AsInt32() => _value;    public static int AsInt32(IntValue value) => value._value;    public static int AlwaysMaxValue(IntValue _) => int.MaxValue;}

如下所示的就是這個(gè)Hijack方法的定義。它的兩個(gè)方法表示調(diào)用原始方法和篡改方法的表達(dá)式,我們利用它們得到對(duì)應(yīng)的MethodInfo對(duì)象。我們利用MethodHandle得到方法句柄,并進(jìn)一步利用GetFunctionPointer方法得到具體的指針地址。有了這兩個(gè)地址,我們就可以計(jì)算出它們之間的偏移量,然后利用Marshal.Copy方法“篡改”了原始方法的指令。具體來說,我們將原始方法的初始指令改為跳轉(zhuǎn)指令JUMP,通過設(shè)置的偏移量跳轉(zhuǎn)到新的方法。

static void Hijack(Expression originalCall, Expression targetCall){    var originalMethod = ((MethodCallExpression)originalCall.Body).Method;    var targetMethod = ((MethodCallExpression)targetCall.Body).Method;    RuntimeHelpers.PrepareMethod(originalMethod.MethodHandle);    RuntimeHelpers.PrepareMethod(targetMethod.MethodHandle);    var sourceAddress = originalMethod.MethodHandle.GetFunctionPointer();    var targetAddress = (long)targetMethod.MethodHandle.GetFunctionPointer();    int offset = (int)(targetAddress - (long)sourceAddress - 5);    byte[] instruction = {        0xE9, // JUMP        (byte)(offset & 0xFF),        (byte)((offset >> 8) & 0xFF),        (byte)((offset >> 16) & 0xFF),        (byte)((offset >> 24) & 0xFF)    };    Marshal.Copy(instruction, 0, sourceAddress, instruction.Length);}

關(guān)鍵詞:

相關(guān)內(nèi)容