Better ObjectDump == Better Crash Logs information
This commit is contained in:
parent
45ce4d79ef
commit
abfd94f0b0
|
@ -1,137 +1,202 @@
|
||||||
|
Imports System.Collections
|
||||||
|
Imports System.Reflection
|
||||||
|
|
||||||
''' <summary>
|
''' <summary>
|
||||||
''' A class to access the dump of variables of an object.
|
''' A class to access the dump of variables of an object.
|
||||||
''' </summary>
|
''' </summary>
|
||||||
Public Class ObjectDump
|
Public Class ObjectDump
|
||||||
|
|
||||||
Private _dump As String = ""
|
Public ReadOnly Property Dump As String = ""
|
||||||
Private _nullReferenceError As Boolean = False
|
|
||||||
|
|
||||||
Public ReadOnly Property Dump() As String
|
Public Sub New(ByVal sender As Object)
|
||||||
Get
|
If sender Is Nothing Then
|
||||||
Return _dump
|
Dump = "Object reference not set to an instance of an object."
|
||||||
End Get
|
|
||||||
End Property
|
|
||||||
|
|
||||||
Public ReadOnly Property NullReferenceError() As Boolean
|
|
||||||
Get
|
|
||||||
Return _nullReferenceError
|
|
||||||
End Get
|
|
||||||
End Property
|
|
||||||
|
|
||||||
''' <summary>
|
|
||||||
''' Creates a new instance of the ObjectDump class and performs a dump on the passed object.
|
|
||||||
''' </summary>
|
|
||||||
Public Sub New(ByVal obj As Object)
|
|
||||||
CreateDump(obj)
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
''' <summary>
|
|
||||||
''' Creates a dump.
|
|
||||||
''' </summary>
|
|
||||||
''' <param name="obj">The object to create a dump from.</param>
|
|
||||||
Private Sub CreateDump(ByVal obj As Object)
|
|
||||||
If obj Is Nothing Then
|
|
||||||
_nullReferenceError = True
|
|
||||||
_dump = "Object reference not set to an instance of an object."
|
|
||||||
Else
|
Else
|
||||||
Dim t As Type = obj.GetType()
|
Dim fields() As FieldInfo = sender.GetType().GetFields(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.Static)
|
||||||
|
Dim properties() As PropertyInfo = sender.GetType().GetProperties(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.Static)
|
||||||
|
|
||||||
Dim fields As Reflection.FieldInfo() = t.GetFields(Reflection.BindingFlags.Public Or
|
Dump =
|
||||||
Reflection.BindingFlags.NonPublic Or
|
"--------------------------------------------------" & vbNewLine &
|
||||||
Reflection.BindingFlags.Instance Or
|
"Generated Fields:" & vbNewLine &
|
||||||
Reflection.BindingFlags.Static)
|
"--------------------------------------------------" & vbNewLine
|
||||||
|
|
||||||
Dim dump As String = ""
|
For Each field As FieldInfo In fields
|
||||||
|
If Dump <> "" Then
|
||||||
For Each field As Reflection.FieldInfo In fields
|
Dump &= vbNewLine
|
||||||
If dump <> "" Then
|
|
||||||
dump &= vbNewLine
|
|
||||||
End If
|
End If
|
||||||
|
|
||||||
Dim accessToken As String = ""
|
Dim fieldAccessToken As String = ""
|
||||||
Dim valueToken As String = "Nothing"
|
Dim fieldNameToken As String = ""
|
||||||
Dim fieldToken As String = field.Name
|
Dim fieldTypeToken As String = ""
|
||||||
Dim typeToken As String = field.FieldType.Name
|
Dim fieldValueToken As String = ""
|
||||||
|
|
||||||
If field.IsPublic = True Then
|
If field.IsPublic Then
|
||||||
accessToken = "Public "
|
fieldAccessToken = "Public "
|
||||||
End If
|
ElseIf field.IsPrivate Then
|
||||||
If field.IsPrivate = True Then
|
fieldAccessToken = "Private "
|
||||||
accessToken = "Private "
|
ElseIf field.IsFamily Then
|
||||||
End If
|
fieldAccessToken = "Protected "
|
||||||
If field.IsFamily = True Then
|
|
||||||
accessToken = "Protected "
|
|
||||||
End If
|
|
||||||
If field.IsStatic = True Then
|
|
||||||
accessToken &= "Shared "
|
|
||||||
End If
|
End If
|
||||||
|
|
||||||
Dim valueObj As Object = field.GetValue(obj)
|
If field.IsStatic Then
|
||||||
If valueObj IsNot Nothing Then
|
fieldAccessToken &= "Shared "
|
||||||
If typeToken.EndsWith("[]") = True Then
|
End If
|
||||||
'Type is array, ToString wont return maintainable material, so we get its content:
|
|
||||||
valueToken = GetArrayDump(valueObj)
|
fieldNameToken = field.Name
|
||||||
ElseIf typeToken = "List`1" Then
|
fieldTypeToken = field.FieldType.Name
|
||||||
'Type is a list, ToString wont return maintainable material, so we get its content:
|
|
||||||
valueToken = GetListDump(valueObj)
|
If field.FieldType.IsArray Then
|
||||||
typeToken = GetListTypeToken(valueObj)
|
fieldValueToken = DumpArray(field.GetValue(sender))
|
||||||
Else
|
ElseIf field.FieldType.IsGenericType Then
|
||||||
valueToken = valueObj.ToString()
|
If field.FieldType.Name = "List`1" Then
|
||||||
|
fieldTypeToken = $"List(Of {field.FieldType.GetGenericArguments()(0).Name})"
|
||||||
|
fieldValueToken = DumpGenericArray(field.GetValue(sender), "List`1")
|
||||||
|
ElseIf field.FieldType.Name = "Dictionary`2" Then
|
||||||
|
fieldTypeToken = $"Dictionary(Of {field.FieldType.GetGenericArguments()(0).Name}, {field.FieldType.GetGenericArguments()(1).Name})"
|
||||||
|
fieldValueToken = DumpGenericArray(field.GetValue(sender), "Dictionary`2")
|
||||||
End If
|
End If
|
||||||
|
ElseIf field.FieldType.Name = "Texture2D" Then
|
||||||
|
fieldValueToken = DumpTexture2D(field.GetValue(sender))
|
||||||
|
Else
|
||||||
|
fieldValueToken = DumpObject(field.GetValue(sender))
|
||||||
End If
|
End If
|
||||||
|
|
||||||
dump &= " " & accessToken & fieldToken & " As " & typeToken & " = " & valueToken
|
Dump &= fieldAccessToken & fieldNameToken & " As " & fieldTypeToken & " = " & fieldValueToken
|
||||||
Next
|
Next
|
||||||
|
|
||||||
_dump = dump
|
Dump &= vbNewLine & vbNewLine &
|
||||||
|
"--------------------------------------------------" & vbNewLine &
|
||||||
|
"Generated Property:" & vbNewLine &
|
||||||
|
"--------------------------------------------------" & vbNewLine
|
||||||
|
|
||||||
|
For Each [property] As PropertyInfo In properties
|
||||||
|
If [property].CanRead Then
|
||||||
|
If Dump <> "" Then
|
||||||
|
Dump &= vbNewLine
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim propertyNameToken As String = ""
|
||||||
|
Dim propertyTypeToken As String = ""
|
||||||
|
Dim propertyValueToken As String = ""
|
||||||
|
|
||||||
|
propertyNameToken = [property].Name
|
||||||
|
propertyTypeToken = [property].PropertyType.Name
|
||||||
|
|
||||||
|
If [property].PropertyType.IsArray Then
|
||||||
|
propertyValueToken = DumpArray([property].GetValue(sender))
|
||||||
|
ElseIf [property].PropertyType.IsGenericType Then
|
||||||
|
If [property].PropertyType.Name = "List`1" Then
|
||||||
|
propertyTypeToken = $"List(Of {[property].PropertyType.GetGenericArguments()(0).Name})"
|
||||||
|
propertyValueToken = DumpGenericArray([property].GetValue(sender), "List`1")
|
||||||
|
ElseIf [property].PropertyType.Name = "Dictionary`2" Then
|
||||||
|
propertyTypeToken = $"Dictionary(Of {[property].PropertyType.GetGenericArguments()(0).Name}, {[property].PropertyType.GetGenericArguments()(1).Name})"
|
||||||
|
propertyValueToken = DumpGenericArray([property].GetValue(sender), "Dictionary`2")
|
||||||
|
End If
|
||||||
|
ElseIf [property].PropertyType.Name = "Texture2D" Then
|
||||||
|
propertyValueToken = DumpTexture2D([property].GetValue(sender))
|
||||||
|
Else
|
||||||
|
propertyValueToken = DumpObject([property].GetValue(sender))
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dump &= "Property " & propertyNameToken & " As " & propertyTypeToken & " = " & propertyValueToken
|
||||||
|
End If
|
||||||
|
Next
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Private Function GetArrayDump(ByVal valueObj As Object) As String
|
Private Function DumpArray(ByVal obj As Object) As String
|
||||||
Dim listDump As String = ""
|
Try
|
||||||
|
If obj IsNot Nothing Then
|
||||||
Dim valueArray As Array = CType(valueObj, Array)
|
Dim listValue As Array = CType(obj, Array)
|
||||||
For i = 0 To valueArray.Length - 1
|
If listValue.Length = 0 Then
|
||||||
If listDump <> "" Then
|
Return "{}"
|
||||||
listDump &= ", "
|
Else
|
||||||
End If
|
Return "{" & String.Join(", ", listValue.Cast(Of Object).Select(Function(a)
|
||||||
If valueArray.GetValue(i) Is Nothing Then
|
Return a.ToString()
|
||||||
listDump &= "Nothing"
|
End Function).ToArray()) & "}"
|
||||||
|
End If
|
||||||
Else
|
Else
|
||||||
listDump &= valueArray.GetValue(i).ToString()
|
Return "Nothing"
|
||||||
End If
|
End If
|
||||||
Next
|
Catch ex As Exception
|
||||||
listDump = "{" & listDump & "}"
|
Return "Array too complex to dump."
|
||||||
Return listDump
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
Private Function GetListDump(ByVal valueObj As Object) As String
|
Private Function DumpGenericArray(ByVal obj As Object, ByVal genericType As String) As String
|
||||||
'Grab the type of the list (List`1):
|
Try
|
||||||
Dim listType As Type = Type.GetType(valueObj.ToString())
|
If obj IsNot Nothing Then
|
||||||
'Get the ToArray method of the list:
|
If genericType = "List`1" Then
|
||||||
Dim method As Reflection.MethodInfo = listType.GetMethod("ToArray", Reflection.BindingFlags.Public Or Reflection.BindingFlags.Instance)
|
Dim listValue As Array = CType(obj.GetType().GetMethod("ToArray").Invoke(obj, Nothing), Array)
|
||||||
|
If listValue.Length = 0 Then
|
||||||
|
Return "{}"
|
||||||
|
Else
|
||||||
|
Return "{" & String.Join(", ", listValue.Cast(Of Object).Select(Function(a)
|
||||||
|
Return a.ToString()
|
||||||
|
End Function).ToArray()) & "}"
|
||||||
|
End If
|
||||||
|
ElseIf genericType = "Dictionary`2" Then
|
||||||
|
Dim dictionaryKeys As Array = CType(obj.GetType().GetProperty("Keys").GetValue(obj), IEnumerable).Cast(Of Object).ToArray()
|
||||||
|
Dim dictonaryValues As Array = CType(obj.GetType().GetProperty("Values").GetValue(obj), IEnumerable).Cast(Of Object).ToArray()
|
||||||
|
|
||||||
Dim listDump As String = ""
|
If dictionaryKeys.Length = 0 OrElse dictonaryValues.Length = 0 Then
|
||||||
|
Return "{}"
|
||||||
'Create an array from the list by invoking its ToArray method. The array is not a generic type anymore, which means we can iterate through it:
|
Else
|
||||||
Dim valueArray As Array = CType(method.Invoke(valueObj, {}), Array)
|
Dim result As String = ""
|
||||||
For i = 0 To valueArray.Length - 1
|
For i As Integer = 0 To dictionaryKeys.Length - 1
|
||||||
If listDump <> "" Then
|
If i > 0 Then
|
||||||
listDump &= ", "
|
result &= ", "
|
||||||
End If
|
End If
|
||||||
If valueArray.GetValue(i) Is Nothing Then
|
result &= "{" & dictionaryKeys.Cast(Of Object)()(i).ToString() & ", " & dictonaryValues.Cast(Of Object)()(i).ToString() & "}"
|
||||||
listDump &= "Nothing"
|
Next
|
||||||
|
Return "{" & result & "}"
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Return "Generic Type too complex to dump."
|
||||||
|
End If
|
||||||
Else
|
Else
|
||||||
listDump &= valueArray.GetValue(i).ToString()
|
Return "Nothing"
|
||||||
End If
|
End If
|
||||||
Next
|
Catch ex As Exception
|
||||||
listDump = "{" & listDump & "}"
|
Return "Generic Type too complex to dump."
|
||||||
Return listDump
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
Private Function GetListTypeToken(ByVal valueObj As Object) As String
|
Private Function DumpTexture2D(ByVal obj As Object) As String
|
||||||
Dim listType As Type = Type.GetType(valueObj.ToString())
|
Try
|
||||||
Return "List<" & listType.GetGenericArguments()(0).Name & ">[]"
|
If obj IsNot Nothing Then
|
||||||
|
Dim textureName As String = ""
|
||||||
|
Dim width As Integer = Convert.ToInt32(obj.GetType().GetProperty("Width").GetValue(obj))
|
||||||
|
Dim height As Integer = Convert.ToInt32(obj.GetType().GetProperty("Height").GetValue(obj))
|
||||||
|
|
||||||
|
If String.IsNullOrEmpty((obj.GetType().GetProperty("Name").GetValue(obj)?.ToString())) Then
|
||||||
|
textureName = """"""
|
||||||
|
Else
|
||||||
|
textureName = obj.GetType().GetProperty("Name").GetValue(obj)?.ToString()
|
||||||
|
End If
|
||||||
|
|
||||||
|
Return $"{{Name = {textureName}, Width = {width}, Height = {height}}}"
|
||||||
|
Else
|
||||||
|
Return "Nothing"
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
Return "Texture2D too complex to dump."
|
||||||
|
End Try
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
End Class
|
Private Function DumpObject(ByVal obj As Object) As String
|
||||||
|
Try
|
||||||
|
If obj IsNot Nothing Then
|
||||||
|
If String.IsNullOrEmpty(obj.ToString()) Then
|
||||||
|
Return """"""
|
||||||
|
Else
|
||||||
|
Return obj.ToString()
|
||||||
|
End If
|
||||||
|
Else
|
||||||
|
Return "Nothing"
|
||||||
|
End If
|
||||||
|
Catch ex As Exception
|
||||||
|
Return "Object too complex to dump."
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
End Class
|
Loading…
Reference in New Issue