Making public the internal field “value__” of dynamic enum from C# .NET 2.0
在Unity中,我创建了一个动态枚举,并成功地将其保存到生成的.dll中,如下所示:msdn文章和此处:C中的动态枚举#我刚刚在动态创建的枚举上添加了flagsattribute
但我注意到内部字段"value_uuuu"在.NET 2.0上是私有的。因此,当我在另一个C应用程序中使用此dll时,我不能直接将枚举值强制转换为int或获取精确的屏蔽值。请注意,在.NET 4.0及更高版本中,"value_uuuu"字段是公共的。还要注意,如果您在c中在2.0 dll中创建一个经典的公共枚举,那么这个"value"也是公共的(在dll中)。
所以我的问题是如何使用EnumBuilder在Mono.NET 2.0中公开这个特殊字段?
这里是生成枚举的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | static bool CreateEnumerators(AppDomain currentDomain, AssemblyName asmName, string enumName, string relativePathName ="") { string targetPathName = currentDomain.BaseDirectory + relativePathName; if (!System.IO.Directory.Exists(targetPathName)) System.IO.Directory.CreateDirectory(targetPathName); // Create a dynamic assembly in the current application domain, // and allow it to be executed and saved to disk. AssemblyBuilder asmBuilder = currentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave, targetPathName); // Define a dynamic module // For a single-module assembly, the module has the same name as the assembly. ModuleBuilder mdlBuilder = asmBuilder.DefineDynamicModule(asmName.Name, asmName.Name +".dll"); // Define a public enumeration and an underlying type of Integer. EnumBuilder enumBuilder = mdlBuilder.DefineEnum(asmName.Name +"." + enumName, TypeAttributes.Public, typeof(int)); // Get data from database int key = 1; foreach (string literalName in enumLiteralNames) { enumBuilder.DefineLiteral(literalName, key); key = key << 1; } // set FlagsAttribute ConstructorInfo cinfo = typeof(FlagsAttribute).GetConstructor(Type.EmptyTypes); CustomAttributeBuilder flagsAttribute = new CustomAttributeBuilder(cinfo, new object[] { }); enumBuilder.SetCustomAttribute(flagsAttribute); // Create the enum Type finished = enumBuilder.CreateType(); // Check if"value__" is private (by default it is from .NET 2.0 to 3.5) Console.WriteLine(" Check special field: "); { FieldInfo fi = finished.GetField("value__", BindingFlags.Instance | BindingFlags.NonPublic); if (fi != null) Console.WriteLine("found as private:" + finished.Name +"." + fi.Name +"{" + fi.Attributes +"}"); } // in .NET 4.0 and above"value__" is part of the public fields Console.WriteLine("Fields:"); foreach (FieldInfo fi in finished.GetFields()) { Console.WriteLine(finished.Name +"." + fi.Name +"" + fi.GetType() +""); } // Finally, save the assembly string assemblyName = asmName.Name +".dll"; asmBuilder.Save(assemblyName); Console.WriteLine(" Created assembly '" + targetPathName + assemblyName +"'"); return true; } |
这里只是一个产生错误的简单用法:
1 2 | MyTypes.MEnum eTypePhysical = MyTypes.MEnum.Physical; Debug.Log("Value =" + (int)eTypePhysical); |
错误:
1 2 | Internal compiler error. See the console log for more information. output was:error CS0656: The compiler required member `MyTypes.MyEnum.value__' could not be found or is inaccessible error CS0656: The compiler required member `MyTypes.MyEnum.value__' could not be found or is inaccessible |
对枚举内部值的任何访问都会产生相同的错误。
我无法在使用Microsft.net 2.0框架生成并使用dll的Visual Studio上获得任何错误。但通过检查dll,我仍然看到动态枚举的"value_uuuuu"是私有的,这显然是导致统一错误的原因。这就是为什么我想知道是否可以使用.NET 2.0的EnumBuilder接口将其声明为公共的原因。
我用System.Reflection on.NET 2.0尝试了很多不同的方法来解决这个问题,但都没有成功。IE:我尝试向程序集添加InternalVisibleToFlags,使用类型生成器从头创建枚举类型。但是它们都不起作用,因为在最近的情况下,显然有一些约束阻止从System.Enum使用继承,当您使用NET Framework 2.0动态构建类型时。我终于切换到为.NET 2.0目标编译的C lib mono.cecil。下面是使用mono.cecil使用公共特殊字段"value_uuu"构建枚举的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | static void CreateEnumAssembly(string asmName, string relativePathName ="") { // get asm version from database Version asmVersion = new Version(0,0,0,0); AssemblyNameDefinition asmNameDef = new AssemblyNameDefinition(asmName, asmVersion); AssemblyDefinition asmDef = AssemblyDefinition.CreateAssembly (asmNameDef, asmName, ModuleKind.Dll); // get enum name from database string enumName ="myEnum"; // define a new enum type TypeDefinition enumTypeDef; asmDef.MainModule.Types.Add (enumTypeDef = new TypeDefinition ( asmName, enumName, TypeAttributes.Public | TypeAttributes.Sealed, asmDef.MainModule.Import(typeof(System.Enum) ))); // - add FlagsAttribute to the enum CustomAttribute flagsAttribute = new CustomAttribute ( asmDef.MainModule.Import(typeof(FlagsAttribute).GetConstructor(Type.EmptyTypes)) ); enumTypeDef.CustomAttributes.Add( flagsAttribute ); // define the special field"value__" of the enum enumTypeDef.Fields.Add (new FieldDefinition ("value__", FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName, asmDef.MainModule.Import (typeof(System.Int32)))); int shift = 0; // get literals and their values from database and define them in the enum foreach (var literalName in literalNames) { FieldDefinition literalDef; enumTypeDef.Fields.Add (literalDef = new FieldDefinition (literalName, FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, enumTypeDef)); System.Int32 key = 1 << shift++; literalDef.Constant = key; } string filename = relativePathName+asmNameDef.Name+".dll"; asmDef.Write(filename); Debug.Log ("Created assembly '"+filename+"'"); } |