我有一个函数,而不是在运行时使用反射创建一个类型,我想在属性网格中显示它。所以我的问题是在定义这种类型时如何设置DisplayNameAttribute或CategoryAttribute等属性。
我的功能如下:
Public Shared Function BuildDynamicTypeWithProperties(ByVal name As String) As Type
Dim myDomain As AppDomain = Thread.GetDomain()
Dim myAsmName As New AssemblyName()
myAsmName.Name = "CustomDevices"
' To generate a persistable assembly, specify AssemblyBuilderAccess.RunAndSave.
Dim myAsmBuilder As AssemblyBuilder = myDomain.DefineDynamicAssembly(myAsmName, _
AssemblyBuilderAccess.RunAndSave)
' Generate a persistable, single-module assembly.
Dim myModBuilder As ModuleBuilder = _
myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name & ".dll")
Dim myTypeBuilder As TypeBuilder = myModBuilder.DefineType(name, TypeAttributes.Public)
' Define a private field to hold the property value.
Dim fbId As FieldBuilder = myTypeBuilder.DefineField("_id", GetType(Integer), FieldAttributes.Private)
Dim fbName As FieldBuilder = myTypeBuilder.DefineField("_name", GetType(String), FieldAttributes.Private)
' The last argument of DefineProperty is Nothing, because the
' property has no parameters. (If you don't specify Nothing, you must
' specify an array of Type objects. For a parameterless property,
' use an array with no elements: New Type() {})
Dim pbId As PropertyBuilder = myTypeBuilder.DefineProperty("iId", _
PropertyAttributes.HasDefault, _
GetType(String), _
Nothing)
Dim pbName As PropertyBuilder = myTypeBuilder.DefineProperty("sName", _
PropertyAttributes.HasDefault, _
GetType(String), _
Nothing)
Dim myAttribute As Type = GetType(MyDisplayNameAttribute)
Dim myConstructorInfo As ConstructorInfo = myAttribute.GetConstructor(New Type(0) {GetType(String)})
Dim attributeBuilder As New CustomAttributeBuilder(myConstructorInfo, New Object(0) {"Name"})
pbName.SetCustomAttribute(attributeBuilder)
' The property set and property get methods require a special
' set of attributes.
Dim getSetAttr As MethodAttributes = MethodAttributes.Public Or MethodAttributes.SpecialName Or MethodAttributes.HideBySig
' Define the "get" accessor method for CustomerName.
Dim mbGetId As MethodBuilder = myTypeBuilder.DefineMethod("GetId", _
getSetAttr, _
GetType(Integer), _
Type.EmptyTypes)
Dim mbGetName As MethodBuilder = myTypeBuilder.DefineMethod("GetName", _
getSetAttr, _
GetType(String), _
Type.EmptyTypes)
Dim ilgGetId As ILGenerator = mbGetId.GetILGenerator()
Dim ilgGetName As ILGenerator = mbGetName.GetILGenerator()
ilgGetId.Emit(OpCodes.Ldarg_0)
ilgGetId.Emit(OpCodes.Ldfld, fbId)
ilgGetId.Emit(OpCodes.Ret)
ilgGetName.Emit(OpCodes.Ldarg_0)
ilgGetName.Emit(OpCodes.Ldfld, fbName)
ilgGetName.Emit(OpCodes.Ret)
' Define the "set" accessor method for CustomerName.
Dim mbSetId As MethodBuilder = myTypeBuilder.DefineMethod("SetId", _
getSetAttr, _
Nothing, _
New Type() {GetType(Integer)})
Dim mbSetName As MethodBuilder = myTypeBuilder.DefineMethod("SetName", _
getSetAttr, _
Nothing, _
New Type() {GetType(String)})
Dim ilgSetId As ILGenerator = mbSetId.GetILGenerator()
Dim ilgSetName As ILGenerator = mbSetName.GetILGenerator()
ilgSetId.Emit(OpCodes.Ldarg_0)
ilgSetId.Emit(OpCodes.Ldarg_1)
ilgSetId.Emit(OpCodes.Stfld, fbId)
ilgSetId.Emit(OpCodes.Ret)
ilgSetName.Emit(OpCodes.Ldarg_0)
ilgSetName.Emit(OpCodes.Ldarg_1)
ilgSetName.Emit(OpCodes.Stfld, fbName)
ilgSetName.Emit(OpCodes.Ret)
' Last, we must map the two methods created above to our PropertyBuilder to
' their corresponding behaviors, "get" and "set" respectively.
pbId.SetGetMethod(mbGetId)
pbId.SetSetMethod(mbSetId)
pbName.SetGetMethod(mbGetName)
pbName.SetSetMethod(mbSetName)
Dim retval As Type = myTypeBuilder.CreateType()
Return retval
End Function
我已尝试过这个,但我没有获得任何DisplayNameAttribute:
Public Shared Sub DisplayNameGridProperty(ByVal obj As Object, ByVal propertyName As String, ByVal displayName As String)
Dim descriptor As PropertyDescriptor = TypeDescriptor.GetProperties(obj.[GetType]())(propertyName)
Dim attribute As DisplayNameAttribute = DirectCast(descriptor.Attributes(GetType(DisplayNameAttribute)), DisplayNameAttribute)
Dim fieldToChange As System.Reflection.FieldInfo = attribute.[GetType]().GetField("displayname", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)
If fieldToChange IsNot Nothing Then
fieldToChange.SetValue(attribute, displayName)
End If
End Sub
有什么想法吗?