锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

C# 类继承中的私有字段都去了哪里?

时间:2022-08-17 22:00:01 xs618b4nal2传感器xs618b1pbl2传感器

最近在看 C 我对类继承中的字段内存布局很好奇 C# 那些继承链 private 字段在哪里? 如何布局内存,毕竟在子类中是无法访问的。

一、举例说明

先举个例子,方便讲述:

internalclassProgram { staticvoidMain(string[]args) { Chinesechinese=newChinese();  intnum=chinese.b;//b不能访问字段,编译报错  Console.WriteLine(num); } }  publicclassPerson { publicinta=10; privateintb=11; }  publicclassChinese:Person { publicintc=12; }  

根据 C# 类继承原则,上述类继承原则chinese.b写作不能编译,因为它属于父类 既然私有字段不能被访问,那么这个private b到底去了哪里?要想找到答案,只能先从chinese看实例中的汇编代码,看看有没有意想不到的收获。

二:查看 chinese 处汇编代码

new chinese()查看下一个断点Visual Stduio 2022反汇编窗口。

接下来我稍微解释一下:

1. 根据 MT 类型 实例化 chinese

07FD6176movecx,87205C4h 07FD617BcallCORINFO_HELP_NEWSFAST(06E30C0h)  

这里的87205C4h就是 Chinese 类型的 MT,然后通过 CLR 下的CORINFO_HELP_NEWSFAST实例化处方法。

2. 使用 chinese 构造函数初始化

07FD6180movdwordptr[ebp-40h],eax 07FD6183movecx,dwordptr[ebp-40h] 07FD6186callCLRStub[MethodDescPrestub]@7e34871e07fd5d20(07FD5D20h) 07FD618Bmoveax,dwordptr[ebp-40h] 

这里的 eax 是CORINFO_HELP_NEWSFAST初始化方法的返回值可以在ecx,dword ptr [ebp-40h]下一个断点,观察其内存布局。

此时的布局图 chinese 这只是一零的默认状态,此时a,b,c三个字段还没有被赋值,那么什么时候被赋值呢?这就是构建函数要做的,也就是以上CLRStub[MethodDescPrestub]@7e34871e07fd5d20 (07FD5D20h)指令,下一步07FD618B再次观察下一个断点0x02C9F528内存地址,即ebp-40接下来我们继续执行位置,截图如下:

从图中可以看出,构造函数执行后,赋值了三个内存地址(变红),依次是a,b,c,这个时候是不是让人眼前一亮?

3. 洞察真相

原来那个b=11没有丢,而是被chinese类给完全继承,布局规则父类字段在前,子类后面的字段有点有趣。下一个问题是如何提取它?

三、如何提取 b 字段

如果是 C 语言,我们用*(pointer 2)可以轻松提取,用托管 C# 如何实现? 复杂的Marshal包装也应变相使用Span这里我就不麻烦了,直接用非安全代码下的指针去摆平,在a字段偏移 4 提取位置, 参考代码如下:

staticvoidMain(string[]args) { unsafe { Chinesechinese=newChinese();  fixed(int*ch=&chinese.a) { intb=*(ch 1);  &nbp;        Console.WriteLine($"b={b}");
                }
            }
        }
    }

哈哈,是不是挺有意思。

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章