ObjectReader

功能:使用BinaryReader读取数据构造一个类,支持除IntPtr以外的基本类型

      
Public NotInheritable Class ObjectReader(Of T As New)
    Shared _gettersAndSetters As New List(Of KeyValuePair(Of MethodInfo, MemberInfo))
    Shared Sub New()
        For Each m In GetType(T).GetMembers(BindingFlags.Public Or BindingFlags.Instance)
            If m.MemberType <> MemberTypes.Field AndAlso m.MemberType <> MemberTypes.Property Then Continue For
            If m.MemberType = MemberTypes.Field Then
                Dim fi = CType(m, FieldInfo)
                If Not fi.FieldType.IsPrimitive Then Continue For
                Dim getter = GetGetter(fi.FieldType)
                If getter Is Nothing Then Continue For
                _gettersAndSetters.Add(New KeyValuePair(Of MethodInfo, MemberInfo)(getter, fi))
            Else
                Dim pi = CType(m, PropertyInfo)
                If Not pi.PropertyType.IsPrimitive Then Continue For
                If Not pi.CanWrite Then Continue For
                Dim getter = GetGetter(pi.PropertyType)
                If getter Is Nothing Then Continue For
                _gettersAndSetters.Add(New KeyValuePair(Of MethodInfo, MemberInfo)(getter, pi))
            End If
        Next
    End Sub

    Public Shared Function Read(ByVal br As BinaryReader) As T
        If _gettersAndSetters.Count = 0 Then Throw New NotSupportedException("No member in specified type is supported and writable")
        If GetType(T).IsValueType Then Return ReadValueType(br) 'VB对结构使用反射时不能声明为Object。。。
        Dim ret As New T
        For Each pair In _gettersAndSetters
            Dim value = pair.Key.Invoke(br, Nothing)
            If pair.Value.MemberType = MemberTypes.Field Then
                CType(pair.Value, FieldInfo).SetValue(ret, value)
            Else
                CType(pair.Value, PropertyInfo).SetValue(ret, value, Nothing)
            End If
        Next
        Return ret
    End Function

    Private Shared Function ReadValueType(ByVal br As BinaryReader) As T
        Dim ret As ValueType = CType(Activator.CreateInstance(GetType(T)), ValueType)
        For Each pair In _gettersAndSetters
            Dim value = pair.Key.Invoke(br, Nothing)
            If pair.Value.MemberType = MemberTypes.Field Then
                CType(pair.Value, FieldInfo).SetValue(ret, value)
            Else
                CType(pair.Value, PropertyInfo).SetValue(ret, value, Nothing)
            End If
        Next
        Return CType(DirectCast(ret, Object), T)
    End Function

    Private Shared Function GetGetter(ByVal type As Type) As MethodInfo
        Dim brType = GetType(BinaryReader)
        Dim ret = brType.GetMethod("Read" & type.Name, BindingFlags.Instance Or BindingFlags.Public, Nothing, CallingConventions.Any, New Type() {}, Nothing)
        Return ret
    End Function

    Private Sub New()

    End Sub
End Class
        

Leave a Reply

Your email address will not be published. Required fields are marked *