公开内部字段“;value__";来自C#.NET 2.0的动态枚举
本文关键字:NET 枚举 动态 来自 内部 字段 value quot | 更新日期: 2023-09-27 18:21:47
在Unity中,我创建了一个动态枚举,并成功地将其保存到生成的.dll中,如下所示:msdn文章和这里:C中的动态枚举#我刚刚在动态创建的枚举上添加了FlagsAttribute
但我注意到内部字段"value__"在.NET 2.0上是私有的。因此,当我在另一个c#应用程序中使用这个dll时,我不能直接将枚举值强制转换为int或获取确切的掩码值。请注意,在.NET 4.0及更高版本中,此"value__"字段是公共的。还要注意,如果您在C#中在2.0 dll中创建一个经典的公共枚举,则该"value__"也是公共的(在dll中)。
所以我的问题是如何使用EnumBuilder在Mono.NET2.0中公开这个特殊字段?
这里我的代码生成枚举:
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("'nCheck special field: 'n");
{
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("'nCreated assembly '" + targetPathName + assemblyName + "'");
return true;
}
这里只是一个简单的使用产生错误:
MyTypes.MEnum eTypePhysical = MyTypes.MEnum.Physical;
Debug.Log("Value =" + (int)eTypePhysical);
错误:
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
对枚举内部值的任何访问都会产生相同的错误。
我在Visual Studio上使用Microsft.NET 2.0 Framework生成dll并使用它时没有得到任何错误。但通过检查dll,我仍然看到动态枚举的"value__"是私有的,这显然是导致Unity中出现错误的原因。这就是为什么我想知道是否可以使用.NET 2.0 的EnumBuilder接口将其声明为公共
我在.NET 2.0上使用System.Reflection尝试了很多不同的方法来解决这个问题,但都没有成功。ie:我试图将internalVisibleToFlags添加到程序集中,通过使用TypeBuilder从头开始创建枚举类型。但它们都不起作用,对于后期的情况,当您使用Net framework 2.0动态构建类型时,显然存在一些限制,阻止使用从System.Enum继承我终于切换到了为.NET 2.0目标编译的c#libMono.Cecil。以下是使用Mono.Cicil.构建带有公共特殊字段"value__"的枚举的代码
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+"'");
}