How can I define a global field in a ModuleBuilder
Asked Answered
I

1

8

I'm making dynamic assemblies with System.Reflection.Emit, and I want to define a module-level field, the kind that can be retrieved with Module.GetField. There are methods in ModuleBuilder to define global methods, but the only thing I could find that looked like a "DefineGlobalField" method are DefineInitializedData and DefineUninitializedData, but for these I specify a size (or initial value, from which the size can be inferred) rather than a type. How can I do this?

Incunabulum answered 31/3, 2018 at 23:34 Comment(2)
huh; I've never noticed that (the GetField with no matching DefineField etc); I love this question! That said; using a static type (TypeBuilder) with static fields there might be a pragmatic workaroundBurushaski
I had considered doing that, but for what I'm doing I wanted something like what F# does, where you can define global functions and variables, but in order to have them accessible them outside the assembly you need to put them in a static class. Thanks for the suggestion anyway.Incunabulum
I
1

After some sifting through the source code of the reflection.emit classes, I discovered that global methods are actually written to a TypeBuilder hiding behind the ModuleBuilder interface. You're really not supposed to be able to access it, but if you get ahold of it via reflection, any fields (and methods) you define on it will become module-global (if you try to define properties or events, no errors will be thrown, but as far as I can tell they don't actually get defined). This is a working solution, but it's obvious you're not supposed to do it, so if anyone comes up with a better one, please post it. In the meantime, here's the code for it:

var moduleData = myModule.GetType().GetField("m_moduleData", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(myModule);
var globalTypeBuilder = (TypeBuilder) moduleData.GetType().GetField("m_globalTypeBuilder", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(moduleData);
globalTypeBuilder.DefineField("myGlobalVar", typeof(int), FieldAttributes.Public | FieldAttributes.Static);
myModule.CreateGlobalFunctions();

Note a) that any fields or methods defined on globalTypeBuilder must be static, b) that there's no advantage that I can tell of defining methods on globalTypeBuilder rather that just using Module.DefineGlobalMethod, and c) even when using globalTypeBuilder you still need to call Module.CreateGlobalFunctions, whether for global methods, global fields, or both.

Incunabulum answered 3/4, 2018 at 0:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.