Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Alright, I've assumed that Reference &amp; ReferenceType look something like this:</p> <pre><code>public class ReferenceType { public string Name { get; set; } public int ID { get; set; } } public class Reference { public string Abbreviation { get; set; } public int ID { get; set; } } </code></pre> <p>and that the class you're trying to generate will looking something like this:</p> <pre><code>public static class Countries { public static readonly ReferenceObject USA = new ReferenceObject(120); public static readonly ReferenceObject CAN = new ReferenceObject(13); //... } </code></pre> <p>What you need to do is created a set of fields (I've made these static and readonly, which is a good practice if you're trying to imitate enumerations) and then populate them from a static constructor, e.g.:</p> <pre><code>AppDomain domain = AppDomain.CurrentDomain; AssemblyName aName = new AssemblyName("DynamicEnums"); AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save); ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll"); // Store a handle to the ReferenceObject(int32 pValue) // constructor. ConstructorInfo referenceObjectConstructor = typeof(ReferenceObject).GetConstructor(new[] { typeof(int) }); foreach (ReferenceType rt in GetTypes()) { TypeBuilder tb = mb.DefineType(rt.Name, TypeAttributes.Public); // Define a static constructor to populate the ReferenceObject // fields. ConstructorBuilder staticConstructorBuilder = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes); ILGenerator staticConstructorILGenerator = staticConstructorBuilder.GetILGenerator(); foreach (Reference r in GetReferences(rt.ID)) { string name = r.Abbreviation.Trim(); // Create a public, static, readonly field to store the // named ReferenceObject. FieldBuilder referenceObjectField = tb.DefineField(name, typeof(ReferenceObject), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.InitOnly); // Add code to the static constructor to populate the // ReferenceObject field: // Load the ReferenceObject's ID value onto the stack as a // literal 4-byte integer (Int32). staticConstructorILGenerator.Emit(OpCodes.Ldc_I4, r.ID); // Create a reference to a new ReferenceObject on the stack // by calling the ReferenceObject(int32 pValue) reference // we created earlier. staticConstructorILGenerator.Emit(OpCodes.Newobj, referenceObjectConstructor); // Store the ReferenceObject reference to the static // ReferenceObject field. staticConstructorILGenerator.Emit(OpCodes.Stsfld, referenceObjectField); } // Finish the static constructor. staticConstructorILGenerator.Emit(OpCodes.Ret); tb.CreateType(); } ab.Save(aName.Name + ".dll"); </code></pre> <p>---- Edit ----</p> <p>To access the values of the fields in the generated DLL, you've got a few options. The first is to run this code, take a copy of the "Dynamic Enums.dll" file it generates and reference that directly from whatever other project includes your runtime code; i.e. you have a project that executes at build time to produce the DLL (as above) and a second, separate project that references the DLL and does the run-time work of your application. The advantage of this is that you can refer to the generated classes directly in code (e.g. <code>SomeMethod(Countries.USA)</code> or <code>if(someVariable == Countries.CAN)</code>), while the downside is you must either work the code above into your build process, or remember to regenerate your DLLs whenever the source database changes. If this is what you're looking for, I'd recommend looking at dedicated code-generation tools like T4, which is built into Visual Studio.</p> <p>The option you seem to be going for above is to directly access the dynamic assembly that you generated while it is still held in memory. To do this, you must mark the assembly as runnable as well as savable:</p> <pre><code>AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave); </code></pre> <p>In truth, you could just mark it as <code>AssemblyBuilderAccess.Run</code> but I'm assuming you still want to save the output.</p> <p>You can then use the FieldInfo.GetValue(object obj) method to get the static value:</p> <pre><code> foreach (Type t in types) { foreach (FieldInfo o in t.GetFields()) { // As this is a static field no instance of type 't' is // required to get the field value, so just pass null ReferenceObject value = o.GetValue(null) as ReferenceObject; Console.WriteLine("{0}.{1} = {2}", t, o.Name, value); } Console.WriteLine(); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload