2015-11-20 62 views
0

我想源動態生成的對象的PropertyGrid。無法正確創建通用CustomAttributeData使用編程方式生成枚舉

有關此屬性的網格組合的選擇,我建立了一個類型轉換器(其中T是一個枚舉,定義的選項列表):

public class TypedConverter<T> : StringConverter where T : struct, IConvertible 
    { 
     ... 

     public override System.ComponentModel.TypeConverter.StandardValuesCollection 
      GetStandardValues(ITypeDescriptorContext context) 
     { 
      if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");    

      string[] values = Enum.GetValues(typeof(T)).OfType<object>().Select(o => o.ToString()).ToArray(); 

      return new StandardValuesCollection(values); 
     } 

    } 

然後我就可以添加自定義屬性的屬性,引用這種類型轉換器,如下(typedConverterGenericType是TypedConverter與枚舉通用參數的類型)

CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(TypeConverterAttribute).GetConstructor(new Type[] { typeof(Type) }), new Type[] { typedConverterGenericType }); 

propertyBuilder.SetCustomAttribute(attributeBuilder); 

這工作,只要枚舉問題是硬編碼:AddTypeConverterAttribute(propertyBuilder, typeof(TypedConverter<Fred>));。在調試器中,屬性的屬性給我{[System.ComponentModel.TypeConverterAttribute(...

然而,當我使用的是動態生成的枚舉(我已經決定在反射正確生成)不工作:

Type enumType = enumBuilder.CreateType();//This generates a proper enum, as I have determined in reflection 

    Type converterType = typeof(TypedConverter<>); 

    Type typedConverterType = converterType.MakeGenericType(enumType); 

    AddTypeConverterAttribute(propertyBuilder, typedConverterType); 

在調試程序,對房地產的屬性,現在給我{System.Reflection.CustomAttributeData},和鑽進這個,我有一個構造函數的錯誤... Mscorlib_CollectionDebugView<System.Reflection.CustomAttributeData>(type.GetProperties()[1].CustomAttributes).Items[4].ConstructorArguments' threw an exception of type 'System.IO.FileNotFoundException'

我做錯了什麼?我如何正確設置TypeConverter屬性?

編輯:如果有人想看看我怎麼加屬性

private void AddTypeConverterAttribute(PropertyBuilder propertyBuilder, Type typedConverterGenericType) 
{ 
    CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(TypeConverterAttribute).GetConstructor(new Type[] { typeof(Type) }), new Type[] { typedConverterGenericType }); 

    propertyBuilder.SetCustomAttribute(attributeBuilder);   
} 

EDIT2

測試證實它是動態創建枚舉的一個問題 - 如果我創建通用鍵入Type typedConverterType = converterType.MakeGenericType(typeof(Fred));它工作正常。

編輯3

我的測試項目可用here。它正在從Resouces中讀取一些JSON,並嘗試生成其類型由該JSON描述的類。

我正在創建一個將生成PropertyGrid的類的實例(Activator.CreateInstance)。爲了在該PropertyGrid上獲得組合選擇,我創建了一個Type,其屬性爲TypedConverter,其中T是一個描述組合選擇中值的枚舉。

這個偉大的工程爲硬編碼的枚舉,而不是由程序生成的那些

+0

你試過'公共EnumBuilder DefineEnum(字符串名稱,TypeAttributes visibility,Type underlyingType);'在'System.Reflection.Emit.ModuleBuilder'中?這是一個例子:https://msdn.microsoft.com/en-us/library/system.reflection.emit.enumbuilder(v = vs.110).aspx – mrtig

+0

@mrtig是的,我沒有包括它爲簡潔的清酒。 'EnumBuilder builder = moduleBuilder.DefineEnum(name,TypeAttributes.Public,typeof(int));''是我如何得到我的enumBuilder。 – johnc

回答

0

我相信我是能夠通過使用不同的動態組件得到這個工作。讓我知道這是否適合你:

AppDomain currentDomain = AppDomain.CurrentDomain; 
AssemblyName enumAssembly = new AssemblyName("enumAssembly"); 

AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
    enumAssembly, AssemblyBuilderAccess.RunAndSave); 
ModuleBuilder mb = ab.DefineDynamicModule(enumAssembly.Name, 
    enumAssembly.Name + ".dll"); 

// Define a public enumeration with the name "Foo" and an 
// underlying type of Integer. 
EnumBuilder eb = mb.DefineEnum("Foo", TypeAttributes.Public, typeof(int)); 

eb.DefineLiteral("Bar", 0); 
eb.DefineLiteral("Baz", 1); 

Type final_foo = eb.CreateType(); 

ab.Save(enumAssembly.Name + ".dll"); 
var converterType = typeof(TypedConverter<>); 

AssemblyName dynamicAsm = new AssemblyName(); 
dynamicAsm.Name = "DynamicAsm"; 

// To generate a persistable assembly, specify AssemblyBuilderAccess.RunAndSave. 
AssemblyBuilder myAsmBuilder = currentDomain.DefineDynamicAssembly(dynamicAsm, 
               AssemblyBuilderAccess.RunAndSave); 
// Generate a persistable single-module assembly. 
ModuleBuilder myModBuilder = 
    myAsmBuilder.DefineDynamicModule(dynamicAsm.Name, dynamicAsm.Name + ".dll"); 

TypeBuilder myTypeBuilder = myModBuilder.DefineType("CustomerData", 
               TypeAttributes.Public); 

PropertyBuilder custNamePropBldr = myTypeBuilder.DefineProperty("elevation", 
               PropertyAttributes.HasDefault, 
               final_foo, 
               null); 


var typedConverterType = converterType.MakeGenericType(final_foo); 

CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(
    typeof(TypeConverterAttribute).GetConstructor(
     new Type[] { typeof(Type) }), 
     new Type[] { typedConverterType } 
    ); 

custNamePropBldr.SetCustomAttribute(attributeBuilder); 
+0

感謝您在星期五arvo的回家路上的火車上。 Promise我會盡快檢查這件事,並讓你知道 – johnc

+0

對不起,夥計們,嘗試不同的程序集,相同的程序集,RunAndSave,只是運行,只是保存,保存和不保存dll。有趣的是,根據dotpeek, – johnc

+0

,我保存的dll顯示爲空。那麼,你試圖做的與我使用的例子有什麼不同? – mrtig

0

我剛纔發現有一個簡單的解決方案來解決這個問題。您需要設置當前域的AssemblyResolve事件,並在事件處理程序返回的請求的組件:

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 

    return AppDomain 
       .CurrentDomain 
       .GetAssemblies() 
       .FirstOrDefault(assembly => assembly.FullName == args.Name); 
} 

這將使您的動態生成的枚舉工作