IL 发出 TypeBuilder 并解析引用
我正在发出几个类,其中一些类需要在自己的构造函数中构造它们的同级。不存在无限递归依赖关系(因此,如果 A 构造 B,B 将不会构造 A;这对于嵌套引用也适用 [A 构造 B 构造 C 意味着 B 和 C 都不会构造 A])。我目前正在编写发出构造函数的代码,但遇到了一些问题。我不知道预先的依赖关系的顺序,所以似乎我有几个选择:
- 以某种方式按依赖关系对类进行排序,并按照依赖关系的顺序“构建”它们,因此更多依赖的类具有有效的要抓取的构造函数引用。
- 在第一遍中单独定义所有构造函数(无需实际发出方法的 IL),以便定义所有构造函数引用。
- 以某种方式缓存已定义的构造函数,以便如果尚未定义构造函数,我可以创建一个占位符 ConstructorBuilder 来获取引用,稍后在构造函数最终发出时将获取该引用。
我目前正在尝试选项(3),我想知道是否已经有一种方法可以从 TypeBuilder 中做到这一点。我的代码看起来像这样(在需要时获取构造函数引用):
var fieldType = DefineType(udtField.Type); // This looks up a cached TypeBuilder or creates a placeholder, if needed
var constructor = fieldType.GetConstructor(Type.EmptyTypes);
if (constructor == null)
{
constructor =
fieldType.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard, Type.EmptyTypes);
}
我的 Build 方法当前像这样启动(我认为如果先前定义了构造函数,这将不起作用):
private void BuildConstructor()
{
var method =
DefinedType.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard, Type.EmptyTypes);
var il = method.GetILGenerator();
有什么方法可以查找先前定义的 ConstructorBuilder(如果已定义),而无需创建我自己的显式缓存?似乎 TypeBuilder 应该知道它,但我看不到任何明显的方法来从 TypeBuilder 文档中查找它。
编辑:
我最终沿着路线 (2) 走下去,它在第一次传递期间定义了所有相关方法,然后在第二次传递中发出 IL。我仍然很好奇是否可以从 TypeBuilder 获取已经在其他地方定义的构建器的 MethodBuilder 实例(或 ConstructorBuilder 实例)。
I am emitting several classes, some of which need to construct their peers in their own constructors. There are no infinite recursive dependencies (so if A constructs B, B won't construct A; this holds true for nested references as well [A constructs B constructs C means neither B nor C will construct A]). I am currently working on the code that emits the constructors and I have a bit of an issue. I don't know the order of dependencies up-front, so it seems that I have a few options:
- Somehow sort the classes by their dependencies and 'build' them in the order of their dependencies, so the more dependent classes have a valid constructor reference to grab.
- Define all of the constructors separately in a first pass (without actually emitting the IL for the methods), so that all of the constructor references are defined.
- Somehow cache the defined constructors so that if the constructor has not yet been defined, I can create a place-holder ConstructorBuilder to get the reference, which will then be grabbed later when the constructor is finally emitted.
I'm currently attempting option (3) and I was wondering if there is already a way to do this from TypeBuilder. I have code that looks like this (to grab a constructor reference when its needed):
var fieldType = DefineType(udtField.Type); // This looks up a cached TypeBuilder or creates a placeholder, if needed
var constructor = fieldType.GetConstructor(Type.EmptyTypes);
if (constructor == null)
{
constructor =
fieldType.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard, Type.EmptyTypes);
}
And my Build method currently starts like this (I don't think this will work if the constructor was previously defined):
private void BuildConstructor()
{
var method =
DefinedType.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard, Type.EmptyTypes);
var il = method.GetILGenerator();
Is there some way that I can look up the ConstructorBuilder that was previously defined (if it has been), without having to create my own explicit cache? It seems like the TypeBuilder should know about it, but I can't see any obvious way to look it up from the TypeBuilder documentation.
EDIT:
I've ended up going down route (2), which defines all of the relevant methods during a first pass, then emits the IL afterward in a second pass. I'd still be curious if it's possible to get MethodBuilder instances (or ConstructorBuilder instances) from the TypeBuilder for builders that have already been defined elsewhere.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不是
TypeBuilder
方面的专家,但它有一个方法.GetConstructor
( http://msdn.microsoft.com/en-us/library/cs01xzbk.aspx ) 和.GetMethod
( http://msdn.microsoft.com/en-us/library/4s2kzbw8.aspx )如果您在缓存的 fieldType 上调用它们,它应该能够返回声明的构造函数...I am no expert on
TypeBuilder
but it has a method.GetConstructor
( http://msdn.microsoft.com/en-us/library/cs01xzbk.aspx ) and.GetMethod
( http://msdn.microsoft.com/en-us/library/4s2kzbw8.aspx ) which should be able to return the declared constructor if you call them on your cached fieldType...通过查看 TypeBuilder 的反汇编代码,您似乎不可能希望每种类型有多个构造函数:
TypeBuilder.DefineConstructor
仅调用DefineConstructorNoLock
,后者仅检查参数和增量constructorCount 字段:因此,如果您只想为每种类型定义一个构造函数,则可以检查此属性(使用反射,因为它是私有字段)并检查其值:
其输出:
这不会为您提供实际的 ConstructorBuilder,但您会知道您已经定义了它。
如果您想实际获取 constructorBuilder,并且不想创建太多重载(例如 1),我会使用扩展方法选择选项 3:
By looking at the disassembled code of TypeBuilder, it appears it's not possible it you want more than one constructor per type :
TypeBuilder.DefineConstructor
just callsDefineConstructorNoLock
which just checks parameters and increments the constructorCount field :So if you just want to define one constructor per type, you can check this property (using reflection, since it's a private field) and check its value :
which outputs :
This won't give you the actual ConstructorBuilder, but you'll know you already defined it.
If you want to actually get the constructorBuilder, and you don't want to create too many overloads (1 for example), I'd go for your option 3 with an extension method: