将属性设置为由Vb .Net中的反射创建的运行时类型

时间:2014-02-10 10:08:15

标签: vb.net reflection attributes reflection.emit system.componentmodel

我有一个函数,而不是在运行时使用反射创建一个类型,我想在属性网格中显示它。所以我的问题是在定义这种类型时如何设置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

有什么想法吗?

0 个答案:

没有答案