所以今天我浏览了ILSpy,以便更好地了解.NET如何在外部方法上执行DllImports,当我遇到奇怪的事情时:
在搜索PInvokeImpl
枚举中定义的枚举值System.Reflection.MethodAttributes
的引用时,我注意到System.Reflection.FieldAttributes
中的匹配定义。
可以肯定的是,这似乎不仅仅是幕后重用枚举值:System.Reflection.FieldInfo
有一个名为IsPinvokeImpl
的公开定义的属性,它专门检查是否存在实现标志已设置。
有趣的是,MethodInfo
类甚至没有此属性 - 必须从MethodImplementationFlags
属性确定。
问题:
字段实际上是否可以实现PInvoke,或者这只是.NET框架中的存根实现,以实现字段装饰和方法装饰之间的平衡?
如果可能,可以在C#中完成,还是这个需要C ++ / CLI的功能?
答案 0 :(得分:6)
当您查看FieldAttributes的MSDN描述时,您会看到它记录为“保留供将来使用”。那个未来还没有到来,所以它的意图没有被确定下来。
FieldAttributes之类的类型不是任意的,它们遵循CLI规范。 Ecma-335指出.NET程序集中的元数据需要看起来如何以及如何解释它。这份文件确实揭示了一个有趣的怪癖。
第II.16.1章描述了字段属性,您将看到元数据标记与FieldAttributes枚举之间的紧密匹配。但请注意,该章中pinvokeimpl
缺少。
第II.2.2.1.5节给出了属性的具体值,它具有值为0x2000的PInvokeImpl。描述是“通过PInvoke转发实现”。与II.23.1.10比较,描述了方法属性。它与字段属性有许多共同的值。
这看起来很像复制/粘贴错误:))
通过.NET Framework源代码深入挖掘,CLR和抖动只考虑方法上的pinvokeimpl。但是,C#编译器似乎基于CLI规范并实际设置了该属性。出现在emit.cpp,RegMeta :: _ DefinePinvokeMap()函数中,如果为字段而不是方法调用此函数,它将设置该属性。这实际上从未发生过。
答案 1 :(得分:3)