【发布时间】:2014-08-02 19:54:30
【问题描述】:
我读过Lazy Initialization,但实际上我不明白如何初始化里面的对象。
这个函数返回一个LazyList,它是Lazy类型的一种自定义实现
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
当我尝试读取 LazyList 的任何项目的属性时,我得到一个 NullReferenceException 异常,我想这是因为对象没有初始化?因为请注意,lazylist 项目计数为“2”,我完全确定我尝试读取的属性不能为空。
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
如果我尝试重现我在上面的代码中所做的事情(尝试读取属性),但在函数内部,那么一切都按预期进行,没有任何空引用异常......就像在这个例子中一样:
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:导入来自dnlib 库。
更新:
我想用更多更好的例子来解释这个问题。
在继续解释之前有两件事:
我确保在所有示例中都存在 TypeName 参数并且找到了 iis,我确保函数返回的对象集合永远不会为空,它的 Collection.Count 为 2 正如我在问题开始时所解释的,所以任何一个都是问题。
好吧,下一个函数返回一个对象列表,这些对象带有一个名为 HasBody 的属性,但此属性 ALWAYS 为空(抛出 NullReference 异常)当它不应该为空时,集合中包含的两个项目的值都应该是True。
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
另一方面,如果我在函数中执行了一个荒谬的修改(请参阅与 tmp 对象相关的更改),该函数将返回一个对象列表,其中 HasBody 属性已初始化,不为空,并且返回列表中包含的 2 个项目是一个 HasBody 属性,其值为 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
那么问题出在哪里以及如何解决?,也许这是针对这种情况的临时解决方案,但返回函数的 methoddef 对象包含很多属性,我需要访问比 @ 更多的属性987654337@ 在未来,所以我真的不能将每个属性“分配”给函数中的 tmp 对象以丑陋的方式解决这个问题......
在这两种情况下,用于循环返回列表的代码是这样的:
注意:请记住,使用第一个函数我无法解析 method.hasbody 属性和 method.body.instructions 属性,两者都会引发 NullReference 异常。
但是使用修改后的函数,我可以解析 method.hasbody 属性,前提是我在返回列表之前将其分配给函数内部的 tmp 变量,如果执行相同操作,method.body.instructions 属性也是如此.
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
【问题讨论】:
-
遇到异常时哪个对象为空?
-
@usr "HasBody" 和 "Body.Instructions" 属性,但我认为确实有很多我没有验证的属性是否为空(当它不应该为空时)。如果可以的话,请查看我的问题更新,感谢您的评论。
标签: .net vb.net lazy-evaluation lazy-initialization dnlib