今天來玩一點(diǎn)變態(tài)的,使用反射獲取到某個(gè)類型的構(gòu)造函數(shù),接著多次對(duì)此類型的某個(gè)對(duì)象調(diào)用構(gòu)造函數(shù)方法。請(qǐng)問此時(shí)會(huì)發(fā)生什么
假定有一個(gè)類型 Foo 的定義如下
class Foo : IDisposable
{
public Foo()
{
}
public int F1 { set; get; }
public int F2 { set; get; } = 10;
}
先使用 RuntimeHelpers 的 GetUninitializedObject 方法創(chuàng)建對(duì)象而不調(diào)用構(gòu)造函數(shù)
var foo = (Foo) RuntimeHelpers.GetUninitializedObject(typeof(Foo));
如果給 Foo 的構(gòu)造函數(shù)添加斷點(diǎn),那么在運(yùn)行上面代碼的時(shí)候,可以看到斷點(diǎn)是不會(huì)進(jìn)入。詳細(xì)請(qǐng)看 dotnet C# 只創(chuàng)建對(duì)象不調(diào)用構(gòu)造函數(shù)方法
此時(shí)雖然 Foo 對(duì)象 foo 創(chuàng)建了,但是此對(duì)象還沒有經(jīng)過構(gòu)造函數(shù)。接下來咱給此對(duì)象賦值,請(qǐng)看代碼
var foo = (Foo)RuntimeHelpers.GetUninitializedObject(typeof(Foo));
foo.F1 = 2;
foo.F2 = 2;
請(qǐng)問此時(shí)的 Foo 里面的 F1 和 F2 屬性分別是什么?當(dāng)然就是 2 了
那如果用反射取出構(gòu)造函數(shù),對(duì) foo 對(duì)象調(diào)用構(gòu)造函數(shù)呢
var constructorInfo = typeof(Foo).GetConstructor(new Type[0]);
constructorInfo!.Invoke(foo, null);
此時(shí)可以看到 foo 對(duì)象里面,兩個(gè)屬性的值不同。具體是啥?自己去本文末尾拉代碼跑跑看
接著再給 foo 對(duì)象賦值,如下面代碼
foo.F1 = 5;
foo.F2 = 5;
然后再次調(diào)用構(gòu)造函數(shù),如下面代碼
foo.F1 = 5;
foo.F2 = 5;
constructorInfo!.Invoke(foo, null);
請(qǐng)問此時(shí)的 F1 和 F2 屬性的值是什么?
回顧一下基礎(chǔ)知識(shí),在類里面寫的 public int F2 { set; get; } = 10;
代碼其實(shí)是 C# 語言帶來的功能,在構(gòu)建的時(shí)候,會(huì)被轉(zhuǎn)寫為大概如下的構(gòu)造函數(shù)代碼
public Foo()
{
F2 = 10;
}
通過 IL 代碼可以看到實(shí)際的邏輯如下
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8
// [53 43 - 53 45]
IL_0000: ldarg.0 // this
IL_0001: ldc.i4.s 10 // 0x0a
IL_0003: stfld int32 KicheyurcherNiwhiyuhawnelkeera.Program/Foo::'<F2>k__BackingField'
// [48 13 - 48 25]
IL_0008: ldarg.0 // this
IL_0009: call instance void [System.Runtime]System.Object::.ctor()
IL_000e: nop
// [49 13 - 49 14]
IL_000f: nop
// [50 13 - 50 14]
IL_0010: ret
} // end of method Foo::.ctor
在 C# 中,其實(shí)構(gòu)造函數(shù)也是一個(gè)函數(shù)而已,如上面代碼,只有寫給 F2 賦值的邏輯,而沒有給 F1 賦值的邏輯。因此在調(diào)用構(gòu)造函數(shù)的時(shí)候,只會(huì)改變 F2 屬性的值,而不會(huì)更改 F1 屬性的任何值。也因?yàn)闃?gòu)造函數(shù)只是一個(gè)函數(shù),因此調(diào)用多次就和調(diào)用一個(gè)方法多次是一樣的
可以通過如下方式獲取本文的源代碼,先創(chuàng)建一個(gè)空文件夾,接著使用命令行 cd 命令進(jìn)入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 5eb2ea112f2861791fafda9ed326657fd05572dd
以上使用的是 gitee 的源,如果 gitee 不能訪問,請(qǐng)?zhí)鎿Q為 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼之后,進(jìn)入 KicheyurcherNiwhiyuhawnelkeera 文件夾
?
本作品采用知識(shí)共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議進(jìn)行許可。歡迎轉(zhuǎn)載、使用、重新發(fā)布,但務(wù)必保留文章署名林德熙(包含鏈接:不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布。如有任何疑問,請(qǐng)與我
本文摘自 :https://blog.51cto.com/u