2014-09-13 62 views
1

在Unity動態枚舉的內部場「value__」,我創建一個動態枚舉和我保存到所生成的成功爲.dll,如下所示:msdn article和這裏:Dynamic enum in C# I」我只是在dyanmically創建的枚舉上添加FlagsAttribute製作公共從C#的.NET 2.0

但我注意到內部字段「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 

任何訪問內部值的枚舉產生相同的錯誤。

我無法在Visual Studio中使用Microsft .NET 2.0 Framework生成dll並使用它。但仍然通過檢查dll,我將動態枚舉的「value__」看作是私有的,顯然是導致Unity出現此錯誤的原因。這就是爲什麼我想知道是否有可能使用.NET 2.0的EnumBuilder接口聲明它是公開的。

+0

你能發表一些利用這個領域的樣本代碼,不能用於你的情況,因爲它是私人的?我不明白你想達到什麼目的。 – 2014-09-13 08:55:05

+0

我試圖澄清它的主體 – xldeveloper 2014-09-13 11:31:35

+0

動態枚舉是一個矛盾的術語。你要麼有一個靜態的值列表,要麼你沒有。這就像說 - 我正在創建一個動態常量... – Goran 2014-09-15 09:05:56

回答

0

我已經嘗試了很多與.NET 2.0上的System.Reflection不同的東西來解決這個問題,而沒有任何成功。即:我試圖將internalVisibleToFlags添加到程序集中,以通過使用TypeBuilder從頭開始創建一個枚舉類型。但他們都沒有工作,對於後期情況顯然有約束,阻止使用繼承從System.Enum當您動態構建一個類型與NET框架2.0 我終於切換到C#lib Mono.Cecil編譯。 NET 2.0目標。 下面是使用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+"'"); 
}