use an enum in an emitted assembly

  • Thread starter Thread starter Moe Green
  • Start date Start date
M

Moe Green

I want create a method which uses a dynamically enum as the type of one
of its parameters.

I can create the assembly with this code:

AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = "EmittedAssembly";

// Create the dynamic assembly.
myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName,
AssemblyBuilderAccess.Save);

// Create a dynamic module.
myModuleBuilder =
myAssemblyBuilder.DefineDynamicModule("EmittedModule",
"EmittedModule.mod");

// Create a dynamic Enum.
myEnumBuilder = myModuleBuilder.DefineEnum("MyNamespace.MyEnum",
TypeAttributes.Public, typeof(Int32));

FieldBuilder myFieldBuilder1
= myEnumBuilder.DefineLiteral("FieldOne", 1);

FieldBuilder myFieldBuilder2
= myEnumBuilder.DefineLiteral("FieldTwo", 2);

myEnumBuilder.CreateType();
myAssemblyBuilder.Save("Ass1.dll");

But, how do I access this in a method.

I want to do something like

class blah {

myMethod( NyNamespace.MyEnum e)
{
...
}}

But it will not let me use this or

void method(a.GetType("MyNamespace.MyEnum") b)
{
}


How can I use an enum in an emitted assembly to define the input
parameter of a method?
 
Hi Moe,

The problem with what you are trying to accomplish is when each part of the
code is defined. The method, and its parameters, are defined at compile
time. However, your enum is defined at run time. The only way to get the
behavior you want is to dynamically build your method at runtime also.

Joe
 
Joe said:
Hi Moe,

The problem with what you are trying to accomplish is when each part of the
code is defined. The method, and its parameters, are defined at compile
time. However, your enum is defined at run time. The only way to get the
behavior you want is to dynamically build your method at runtime also.

Joe

Thanks, Joe.

I've seen code showing how to create the Enum dynamically at run time.

But when it comes time to utilize that as the input type of an actual method

void myMethod ( myDynamicEnum mde) { .... }

I can't seem to make heads of tails of it !

For example, I can globally declare the Assembly at the class level, but
if I then try and define a Type using the GetType method of Assembly,
Visual Studio barfs on me.

Can it be done? It seems doable...but I'm just missing some key trick...
 
Hi Steve,

Here are a few tips:

1. When you instantiate your AssemblyBuilder, you need to change its access
from AssemblyBuilderAccess.Save to AssemblyBuilderAccess.RunAndSave.

2. Get an instance of your enum via the Enum.ToObject() method.

3. Write the code for the method you want to dynamically generate. Then
use ILDASM to see the IL it generates. Use the compiler generated IL to
figure out what opcodes to use in the ILGenerator.Emit calls.

Here's an example of what you need to do:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Test
{
static void Main()
{
AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = "EmittedAssembly";

AppDomain myAppDomain = AppDomain.CurrentDomain;

// Create the dynamic assembly.
AssemblyBuilder myAssemblyBuilder =
myAppDomain.DefineDynamicAssembly(myAssemblyName,
AssemblyBuilderAccess.RunAndSave);

// Create a dynamic module.
ModuleBuilder myModuleBuilder =
myAssemblyBuilder.DefineDynamicModule("EmittedModule",
"EmittedModule.mod");

// Create a dynamic Enum.
EnumBuilder myEnumBuilder = myModuleBuilder.DefineEnum("MyEnum",
TypeAttributes.Public, typeof(Int32));

FieldBuilder myFieldBuilder1
= myEnumBuilder.DefineLiteral("FieldOne", 1);

FieldBuilder myFieldBuilder2
= myEnumBuilder.DefineLiteral("FieldTwo", 2);

Type myEnumType = myEnumBuilder.CreateType();

object anEnum = Enum.ToObject(myEnumType, 2);

TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("MyType");

MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod(
"MyMethod",
MethodAttributes.Public,
typeof(void),
new Type[] { myEnumType });

ILGenerator myILGenerator = myMethodBuilder.GetILGenerator();
myILGenerator.Emit(OpCodes.Ldarg_1);
myILGenerator.Emit(OpCodes.Box, myEnumType);
MethodInfo myWriteLineMethodInfo =
typeof(Console).GetMethod("WriteLine",new Type[]{typeof(object)});
myILGenerator.Emit(OpCodes.Call, myWriteLineMethodInfo);
myILGenerator.Emit(OpCodes.Ret);

Type myType = myTypeBuilder.CreateType();

object myInstance = Activator.CreateInstance(myType);

MethodInfo myMethod = myType.GetMethod("MyMethod");

myMethod.Invoke(myInstance, new object[] { anEnum });

myAssemblyBuilder.Save("Ass1.dll");

Console.ReadLine();
}
}


Joe
 
This is very cool stuff, Joe, thanks for your help.

I got the base working now, and I'm going to walk through your code as well.

Reflection is the coolest.

I think I read that Reflection can be performed direct into memory (not
just saving to a file)...is that true? Can I replace a loaded dll with
the new dynamic dll without going through saving to a file and calling?
 
Sure, just use AssemblyBuilderAccess.Run when instantiating your
AssemblyBuilder and skip the call to Save().

Joe
--
http://www.csharp-station.com

Moe Green said:
This is very cool stuff, Joe, thanks for your help.

I got the base working now, and I'm going to walk through your code as
well.

Reflection is the coolest.

I think I read that Reflection can be performed direct into memory (not
just saving to a file)...is that true? Can I replace a loaded dll with
the new dynamic dll without going through saving to a file and calling?


Joe said:
Hi Steve,

Here are a few tips:

1. When you instantiate your AssemblyBuilder, you need to change its
access from AssemblyBuilderAccess.Save to
AssemblyBuilderAccess.RunAndSave.

2. Get an instance of your enum via the Enum.ToObject() method.

3. Write the code for the method you want to dynamically generate. Then
use ILDASM to see the IL it generates. Use the compiler generated IL to
figure out what opcodes to use in the ILGenerator.Emit calls.

Here's an example of what you need to do:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Test
{
static void Main()
{
AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = "EmittedAssembly";

AppDomain myAppDomain = AppDomain.CurrentDomain;

// Create the dynamic assembly.
AssemblyBuilder myAssemblyBuilder =
myAppDomain.DefineDynamicAssembly(myAssemblyName,
AssemblyBuilderAccess.RunAndSave);

// Create a dynamic module.
ModuleBuilder myModuleBuilder =
myAssemblyBuilder.DefineDynamicModule("EmittedModule",
"EmittedModule.mod");

// Create a dynamic Enum.
EnumBuilder myEnumBuilder = myModuleBuilder.DefineEnum("MyEnum",
TypeAttributes.Public, typeof(Int32));

FieldBuilder myFieldBuilder1
= myEnumBuilder.DefineLiteral("FieldOne", 1);

FieldBuilder myFieldBuilder2
= myEnumBuilder.DefineLiteral("FieldTwo", 2);

Type myEnumType = myEnumBuilder.CreateType();

object anEnum = Enum.ToObject(myEnumType, 2);

TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("MyType");

MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod(
"MyMethod",
MethodAttributes.Public,
typeof(void),
new Type[] { myEnumType });

ILGenerator myILGenerator = myMethodBuilder.GetILGenerator();
myILGenerator.Emit(OpCodes.Ldarg_1);
myILGenerator.Emit(OpCodes.Box, myEnumType);
MethodInfo myWriteLineMethodInfo =
typeof(Console).GetMethod("WriteLine",new Type[]{typeof(object)});
myILGenerator.Emit(OpCodes.Call, myWriteLineMethodInfo);
myILGenerator.Emit(OpCodes.Ret);

Type myType = myTypeBuilder.CreateType();

object myInstance = Activator.CreateInstance(myType);

MethodInfo myMethod = myType.GetMethod("MyMethod");

myMethod.Invoke(myInstance, new object[] { anEnum });

myAssemblyBuilder.Save("Ass1.dll");

Console.ReadLine();
}
}


Joe
 
Back
Top