如何在C#中使用.NET表达式API为枚举创建赋值表达式

问题描述:

使用TypeBuilder(.NET 4.6)API我在运行时创建了Enum对象; w.r.t.动态代码生成这里是产率:如何在C#中使用.NET表达式API为枚举创建赋值表达式

public enum WorkflowModelProperty 
    { 
     WorkflowModelDate = 1, 
     WorkflowModelTime = 2, 
     WorkflowModelHeader = 3, 
     WorkflowModelTitle = 4, 
     WorkflowModelID  = 5, 
     WorkflowModelOntologyRoot = 6, 
    } 

这里是用来生成枚举对象的代码:

// 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); 

这里是添加字段成员到枚举TypeBuilder对象的代码:

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); 
           }, 

在这一点上我已经得到了产生枚举类型的全烤实例。现在,我想创建对枚举类型的动态生成实例的分配 - 这里的代码:

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(); 
           }); 

下面是运行时错误消息:类型的表达式WorkflowMessagingCommands'不能用于分配键入“ WorkflowMessagingCommands'

我错过了什么?

在您的代码的第一步中,您必须更改方法的第一个参数Expression.Variable。此方法的第一个参数应该是您的类型,并且您没有为变量创建传递正确的类型。

您必须使用这样的:

var enumCode = Expression.Variable(codeForEnumType, "enumCode"); 
+0

是啊,我知道它是一个轻微的疏忽 - 谢谢你阿尔贝托那确实解决问题。 –

+0

仅供参考 - 当我使用** EnumBuilder **代替** TypeBuilder **时,此代码不起作用。 –