两个 TypeBuilder 互相调用非法?

发布于 2024-08-02 09:03:05 字数 291 浏览 2 评论 0原文

我正在生成(使用 System.Reflection.Emit)两种类型:将它们称为 foo、bar。问题是,foo 实例化并调用 bar,而 bar 使用 foo。

当我创建 bar 时一切正常,但是当我开始生成 foo 时,我得到 typeloadException 说找不到类型 foo 。当我尝试将构造函数定位到 bar(它的参数之一采用 foo)时,就会发生这种情况(可能是因为错误很模糊)。

当 bar 是 foo 中的嵌套类型时,此方法有效。

所以我的问题是 - 让两种类型互相调用是非法的,还是我做错了?

I'm generating (using System.Reflection.Emit) two types: call them foo, bar. The catch is, foo instantiates and calls bar, and bar uses foo.

All works fine when I create bar, but when I then start generating foo, I get typeloadexception saying that type foo could not be found. It happens (probably, as the error was vague) when I try to locate the constructor to bar, which as one of its parameters takes foo.

This works when bar is nested type in foo.

So my question is - is it illegal to have two types calling each other like this, or am I doing it wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

傻比既视感 2024-08-09 09:03:05

尝试手动查找构造函数可能很困难,但您应该仍然拥有之前生成的构造函数?你尝试过传递那个吗?我会尝试做一个例子...

    var assemblyName = new AssemblyName("tmp");
    var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    var module = assembly.DefineDynamicModule("tmp");
    var foo = module.DefineType("Foo");
    var bar = module.DefineType("Bar");
    var barOnFoo = foo.DefineField("bar", bar, FieldAttributes.Private);
    var fooOnBar = bar.DefineField("foo", foo, FieldAttributes.Private);
    var barCtor = bar.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { foo });
    var il = barCtor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stfld, fooOnBar);
    il.Emit(OpCodes.Ret);
    var fooCtor = foo.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
    il = fooCtor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, barCtor);
    il.Emit(OpCodes.Stfld, barOnFoo);
    il.Emit(OpCodes.Ret);

    // create the actual types and test object creation
    Type fooType = foo.CreateType(), barType = bar.CreateType();
    object obj = Activator.CreateInstance(fooType);

我可以添加额外的代码来检查结果,但在调试器中查看 obj 会更容易,您可以看到字段等

。更复杂的情况 - 不要忘记您不需要编写方法(IL)的主体来使用它......您可以先编写所有签名(DefineMethodDefineConstructor 等),然后在后面写入所有主体,从而允许完全循环代码。

Trying to locate the constructor manually may be hard, but you should still have the one you generated earlier? Have you tried passing it that one? I'll try to do an example...

    var assemblyName = new AssemblyName("tmp");
    var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    var module = assembly.DefineDynamicModule("tmp");
    var foo = module.DefineType("Foo");
    var bar = module.DefineType("Bar");
    var barOnFoo = foo.DefineField("bar", bar, FieldAttributes.Private);
    var fooOnBar = bar.DefineField("foo", foo, FieldAttributes.Private);
    var barCtor = bar.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { foo });
    var il = barCtor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stfld, fooOnBar);
    il.Emit(OpCodes.Ret);
    var fooCtor = foo.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
    il = fooCtor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, barCtor);
    il.Emit(OpCodes.Stfld, barOnFoo);
    il.Emit(OpCodes.Ret);

    // create the actual types and test object creation
    Type fooType = foo.CreateType(), barType = bar.CreateType();
    object obj = Activator.CreateInstance(fooType);

I could add extra code to check the result, but it is easier just to look at obj in the debugger, and you can see the fields etc.

For more complex cases - don't forget that you don't need to write the body of a method (the IL) to use it... you can write all the signatures first (DefineMethod, DefineConstructor, etc), and then write all the bodies after, allowing fully cyclic code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文