在Unity中,我创建了一个动态枚举,并将其成功保存到生成的.dll中,如下所示:msdn article和此处:Dynamic enum in C# 我刚刚在dyanmically创建的枚举
上添加了FlagsAttribute但我注意到内部字段“value__”在.NET 2.0上是私有的。因此,当我在另一个c#应用程序中使用此dll时,我无法直接将枚举值转换为int或获取确切的屏蔽值。请注意,在.NET 4.0及更高版本中,此“value__”字段是公共的。另请注意,如果您在C#中创建2.0 dll中的经典公共枚举,则此“value__”也是公共的(在dll中)。
所以我的问题是如何使用EnumBuilder在Mono .NET 2.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
对枚举内部值的任何访问都会产生相同的错误。
我无法使用Microsft .NET 2.0 Framework在Visual Studio上获得任何错误来生成dll并使用它。但是仍然通过检查dll我看到动态枚举的“value__”为私有,这显然是Unity中导致错误的原因。这就是为什么我想知道是否可以使用.NET 2.0的EnumBuilder接口声明它是公开的
答案 0 :(得分:0)
我在.NET 2.0上使用System.Reflection尝试了很多不同的东西来解决这个问题而没有任何成功。即:我尝试将internalVisibleToFlags添加到程序集中,以使用TypeBuilder从头开始创建枚举类型。但是它们都没有工作,因为在最近的情况下,当你使用Net framework 2.0动态构建一个类型时,显然存在阻止从System.Enum使用继承的限制 我终于切换到为.NET 2.0目标编译的c#lib Mono.Cecil。 下面是使用Mono.Cecil使用公共特殊字段“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+"'");
}