Using the TypeBuilder (.NET 4.6) API I have created a Enum object at runtime; w.r.t. dynamic code generation here is the yield:
public enum WorkflowModelProperty
{
WorkflowModelDate = 1,
WorkflowModelTime = 2,
WorkflowModelHeader = 3,
WorkflowModelTitle = 4,
WorkflowModelID = 5,
WorkflowModelOntologyRoot = 6,
}
Here is the code used to generate the enum object:
// Create a dynamic assembly in the current application domain and allow it to be executed.
var dynamicAssemblyName = new AssemblyName(theAssemblyName);
var assemlbyBuilderFactory = await CurrentAppDomain.DefineDynamicAssembly, dynamicAssemblyName, BuilderAccess);
var moduleBuilderFactory = await assemlbyBuilderFactory.DefineDynamicModule(theLibraryModuleName, dynamicAssemblyName.Name + DLLPrefix);
TypeBuilder enumTypeBuilderFactory = moduleBuilderFactory.DefineType(theEnumDefinitionName, TypeAttributes.Public, typeof (Enum), null);
enumTypeBuilderFactory?.DefineField("value__", typeof(int), FieldAttributes.Private | FieldAttributes.SpecialName);
Here is the code that adds Field Members to the Enum TypeBuilder object:
EnumHostInfoSetCache = EnumHostInfoSetCacheBuilder.ToImmutable();
// Okay we need to check to see if the internal states validate the DSL model passed into us.
enumHostInfoSet = EnumHostInfoSetCache.SingleOrDefault(
enumHostEntry =>
(enumHostEntry.Value.GetValueOrDefault().EnumDefintionName ==
localTypeDefinitionDSL.TheEnumDefinitionName)).Value;
var enumBuilder = await enumHostInfoSet.GetValueOrDefault().EnumTypeBuilder;
EnumFieldBuilderMaterializer = EnumFieldBuilderConnectedObserver?.
SubscribeOn(Scheduler.CurrentThread).Subscribe(
delegate(Tuple<string, TEnumBaseType> enumFieldMetadata)
{
try
{
var enumFieldName = enumFieldMetadata.GetEnumFieldMemberName();
var enumFieldValue = enumFieldMetadata.GetEnumFieldMemberValue();
// Code Generate the Enum Field, thus creating a literal definition
var enumFieldBuilder = enumBuilder.DefineField(enumFieldName, enumBuilder,
FieldAttributes.Public | FieldAttributes.Literal | FieldAttributes.Static);
// Set the Constant value on
enumFieldBuilder.SetConstant(enumFieldValue);
// Okay, at this point the Enum Metadata DSL Model is hooked-up to our source here and is not connected to
// the Hot Observable source here in the Agent; as we push data into memory the Model should load itself.
EnumFieldBuilderCacheBuilder?.Add(enumFieldName, enumFieldBuilder);
}
catch (Exception e)
{
throw new ProtoNexusAPIException(e.Message);
}
},
delegate(Exception exception)
{
CodeGenExceptionHandler(exception);
},
At this point I've got a fully-baked instance of the generated Enum Type. Now I want to create a assignment of on a dynamically generated instance of the enum type - here's that code:
delegate() // OnCompleted() Implementation!
{
// Step 0: Prepare for generation of Dynamic Enum Assignment via Expression APIs
var codeForEnumType = enumBuilder.CreateType();
var enumInstance = Activator.CreateInstance(Enum.GetUnderlyingType(codeForEnumType));
var enumInstanceX = Activator.CreateInstance(codeForEnumType);
var recordOfEnumFields = enumBuilder.DeclaredFields;
// Okay let's set-up for dynamic materialization of Enum Assignment Expression code:
try
{
// Experimental code for learning and teaching...
var rightSideExp = Enum.ToObject(codeForEnumType, 2); // I know I can get to this ordinal value
// Step 1: Enum has been created and is ready for use.
var enumCode = Expression.Variable(enumBuilder, "enumCode");
// Step 2: Okay we are ready to make the Assignment via the Expression.Assign API. We can set this up a number of ways
var enumAssignmentSource = Expression.Constant(rightSideExp); // This is the value we want to assign
var enumRightHandSideA = Expression.Constant(Enum.ToObject(codeForEnumType, 1), codeForEnumType);
//var enumRightHandSideB = Expression.Constant(3, codeForEnumType); // This DOES NOT WORK! - Argument does not Match!
var enumRightHandSideC = Expression.Constant(enumInstanceX, codeForEnumType);
// Step 3:
var workFlowDisplayCommand = Expression.Assign(enumCode, enumRightHandSideA); // DOES NOT WORK - Argument does not Match!
workFlowDisplayCommand = Expression.Assign(enumCode, enumRightHandSideC); // DOES NOT WORK
workFlowDisplayCommand = Expression.Assign(enumCode, enumAssignmentSource); // DOES NOT WORK
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
localTypeDefinitionDSL.SetEnumType(codeForEnumType, ref recordOfEnumFields);
localTypeDefinitionDSL.SetEnumTypeInstance(enumInstance);
if (EnumFieldBuilderCacheBuilder != null)
{
try
{
// Setup the Rx HOT Subscription:
// Step 1: Load-up our Immutable Collection
EnumFieldBuilderCache = EnumFieldBuilderCacheBuilder?.ToImmutable();
// Step 2: Create our Observable Source
EnumFieldBuilderCollectionSource =
EnumFieldBuilderCache?.ToObservable(Scheduler.CurrentThread);
// Step 3: Convert the Collection Source to a Hot Observable
EnumFieldBuilderSubscriptionSource =
EnumFieldBuilderCollectionSource?.Publish();
EnumFieldBuilderSubscriptionSource.ObserveOn(Scheduler.CurrentThread);
localTypeDefinitionDSL.LoadFieldBuilderSubscription(
EnumFieldBuilderSubscriptionSource);
}
catch (Exception e)
{
throw new ApplicationException(e.Message);
}
}
EnumFieldBuilderMaterializer?.Dispose();
});
Here is the runtime error message: Expression of type 'WorkflowMessagingCommands' cannot be used for assignment to type 'WorkflowMessagingCommands'
What am I missing?!
In first step of your code, you must change the first parameter of Expression.Variable
method. The first parameter of this method, should be your type, and you are not passing the properly type for variable creating.
You must use like this:
var enumCode = Expression.Variable(codeForEnumType, "enumCode");