I've read about Lazy Initialization but practically I don't understand how to initialize the objects inside.
This function returns a LazyList
which is a kind of custom implementation of a Lazy type
Public Function GetMethods(ByVal Assembly As String,
ByVal TypeName As String) 'As List(Of MethodDef) ' As MethodDef()
Dim methods As LazyList(Of MethodDef) = Nothing
Using ass As ModuleDefMD = ModuleDefMD.Load(Assembly)
For Each t As TypeDef In ass.GetTypes
If t.HasMethods AndAlso t.Name.String.Equals(TypeName, StringComparison.OrdinalIgnoreCase) Then
methods = t.Methods
' MsgBox(t.Methods.GetType.Name) ' Result: LazyList'1
Exit For
End If
Next t
Return methods
End Using
End Function
When I try to read a property of any item of the LazyList I get a NullReferenceException
exception, I suppose that this is because the object is not initialized? 'cause note that the lazylist item count is "2", and I'm totally sure that the property which I try to read can't be null.
Imports dnlib.DotNet
Imports dnlib.DotNet.Emit
Imports dnlib.Utils
Dim methods As LazyList(Of MethodDef) = GetMethods("C:\WindowsApplication.exe", "Main")
MsgBox(methods.IsInitialized(0)) ' Result: False
MsgBox(methods.Count) ' Result: 2
For Each method As MethodDef In methods
' NullReferenceException exception here:
MsgBox(method.Name)
' NullReferenceException exception here too (reading m.hasbody):
If method.HasBody Then
Dim sb As New System.Text.StringBuilder
With sb
.AppendLine(String.Format("Method Instructions: {0}", Environment.NewLine &
String.Join(Environment.NewLine, method.Body.Instructions)))
End With
Debug.WriteLine(sb.ToString)
End If
Next method
If I try to reproduce what I do in the code above (try to read the properties) but inside the function then all goes as expected without any nullreference exception... like in this example:
public function GetMethods (...)
' deleted code...
If t.HasMethods AndAlso t.Name.String.Equals(TypeName, StringComparison.OrdinalIgnoreCase) Then
methods = t.Methods
For Each m In methods
MsgBox(m.Name) ' no exceptions
MsgBox(m.HasBody) ' no exceptions
Next
End If
' deleted code...
end function
PS: The imports are from dnlib library.
UPDATE:
I would like to explain the problem with more and better examples.
Two thinngs before continue explaining:
I ensured that in all examples the TypeName
parameter exists and iis found, I've ensured that the returned collection of objects by the function never is empty, it has an Collection.Count of 2 as I've explained at the start of the question, so any of that is the problem.
Well, the next function returns a List of objects, those objects come with a property named HasBody
but this property ALWAYS is empty (throwing a NullReference exception) when it should not be empty, the value should be True for the both items contained in the collection.
Public Function GetMethods(ByVal Assembly As String,
ByVal TypeName As String) As List(Of MethodDef)
Dim methods As List(Of MethodDef) = Nothing
Using ass As ModuleDefMD = ModuleDefMD.Load(Assembly)
For Each t As TypeDef In ass.GetTypes
If t.HasMethods AndAlso t.Name.String.Equals(TypeName, StringComparison.OrdinalIgnoreCase) Then
methods = t.Methods.ToList
Exit For
End If
Next t
Return methods
End Using
End Function
By the other hand, If I perform a ridiculous modification in the function (see the changes related to the tmp
object) the function returns a list of objects where the HasBody
property is initialized, is not empty, and the 2 items contained in the returned list a HasBody
property with a value of True.
Public Function GetMethods(ByVal Assembly As String,
ByVal TypeName As String) As List(Of MethodDef)
Dim methods As List(Of MethodDef) = Nothing
Dim tmp As Object
Using ass As ModuleDefMD = ModuleDefMD.Load(Assembly)
For Each t As TypeDef In ass.GetTypes
If t.HasMethods AndAlso t.Name.String.Equals(TypeName, StringComparison.OrdinalIgnoreCase) Then
methods = t.Methods.ToList
For Each m In methods
tmp = m.HasBody
Next
Exit For
End If
Next t
Return methods
End Using
End Function
So where is the problem here and how to fix it?, maybe that is a temporal solution for this situation but the methoddef
object that returns the function contains a lot of properties and I need to access to more properties than HasBody
in the future so I really can't be "assigning" each property to the tmp
object in the function to solve that in a ugly way...
and the code used for loop through the returned List in both cases whas this:
Note: remember that, with the first function I can't parse the method.hasbody
property and neither the method.body.instructions
property, both throw a NullReference exception.
But with the modified function I can parse the method.hasbody
property only if I've assigned it to the tmp
variable inside the function before returning the List, and the same for the method.body.instructions
property if did the same.
Dim methods As List(Of MethodDef) =
GetMethods("C:\WindowsApplication.exe", "Main")
For Each method As MethodDef In methods
MsgBox(method.Name)
If method.HasBody Then
Dim sb As New System.Text.StringBuilder
With sb
.AppendLine(String.Format("Method Instructions: {0}", Environment.NewLine &
String.Join(Environment.NewLine, method.Body.Instructions)))
End With
MsgBox(sb.ToString)
End If
Next method