.net 如何初始化惰性列表?
我读过,但实际上我不知道如何初始化里面的对象 此函数返回一个.net 如何初始化惰性列表?,.net,vb.net,lazy-evaluation,lazy-initialization,dnlib,.net,Vb.net,Lazy Evaluation,Lazy Initialization,Dnlib,我读过,但实际上我不知道如何初始化里面的对象 此函数返回一个LazyList,它是一种类型的自定义实现 当我尝试读取LazyList的任何项的属性时,我得到一个NullReferenceException异常,我想这是因为对象未初始化?”原因请注意,lazylist项计数为“2”,我完全确定我尝试读取的属性不能为null Imports dnlib.DotNet Imports dnlib.DotNet.Emit Imports dnlib.Utils Dim methods As L
LazyList
,它是一种类型的自定义实现
当我尝试读取LazyList的任何项的属性时,我得到一个NullReferenceException
异常,我想这是因为对象未初始化?”原因请注意,lazylist项计数为“2”,我完全确定我尝试读取的属性不能为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
如果我试图重现我在上面代码中所做的(尝试读取属性),但是在函数内部,那么一切都会按照预期进行,没有任何nullreference异常。。。如本例所示:
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:导入来自库
更新:
我想用更多更好的例子来解释这个问题
在继续解释之前有两件事:
我确保在所有示例中,TypeName
参数存在,并且找到了iis,我确保函数返回的对象集合从不为空,它有一个集合。计数2,正如我在问题开始时解释的,所以这就是问题所在
好的,下一个函数返回一个对象列表,这些对象带有一个名为
HasBody
的属性,但是这个属性总是为空(抛出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
属性被初始化,并且不是空的,返回的列表中包含的两项是一个值为True的HasBody
属性
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
对象包含很多属性,我需要在将来访问比HasBody
更多的属性,所以我真的不能“赋值”函数中tmp
对象的每个属性以一种丑陋的方式解决该问题
在这两种情况下,用于循环返回列表的代码是:
注意:请记住,对于第一个函数,我不能解析方法.hasbody
属性,也不能解析方法.body.instructions
属性,两者都会引发NullReference异常
但是通过修改后的函数,我可以解析方法.hasbody
属性,前提是我在返回列表之前已将其分配给函数中的tmp
变量,如果方法.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
我认为这是第一个问题:
Public Function GetMethods(ByVal Assembly As String,
ByVal TypeName As String) 'As List(Of MethodDef)
指定返回类型,它可能会工作:As LazyList(属于MethodDef)
当在程序集中找不到TypeName
时,也会发生这种情况。在这种情况下,您的懒散列表仍然是空的,并导致NRE。你应该查看报税表-我认为这与懒汉名单无关(目前):
试验台:
Dim methods As LazyList(Of MethodDef) = Nothing
在按钮中单击:
methods = Test_Handler("Test2")
For Each meth As MethodDef In methods
If meth.HasBody Then
Console.WriteLine("{0} has a body", meth.Name)
Else
Console.WriteLine("{0} has NO body", meth.Name)
End If
Next
测试处理程序本质上就是您所拥有的&=(MethodDef的)懒散列表
。输出:
.ctor has a body
testfunction has a body
Foo has a body
Bar has a body
ziggy has a body
接下来可能会出现更大的问题:。。。我不明白如何初始化里面的对象
LazyList中存储的是这些MethodDef
对象——它们已经实例化了TypeDef.Methods
实际上返回的是MethodDef
的IList,其中包含懒散列表的唯一原因是您的代码以这种方式存储它们
如果你想调用他们描述的方法,我很确定你不能用MethodDef
作为起点。它们只是描述方法特征的元数据。您已经知道它们来自TypeName
,因此要调用其中一个方法,您必须拥有该类型的实例
不知道您想做什么,但是对于元数据集合来说,似乎不需要懒散列表
对象浏览器中
方法
的定义是IList
,源代码还显示:
public ThreadSafe.IList<MethodDef> Methods
您可能太聪明了,尝试只执行以下操作:返回t.Methods
,并获得有关LastList转换到List的转换错误。但是,您得到的方法对象集已经实例化,因此如果您得到的是NREs,则可能会有其他问题
这解决了问题:
Using ass As ModuleDefMD = ModuleDefMD.Load(Assembly)
方法def的列表在内部是一个LazyList,在调用其上的属性或方法之前不会实例化。举例来说,他们(显然)需要访问创建他们的东西。因此,请参考一些无害的内容,以便处理ModuleDefMD
Dim methods As New List(Of MethodDef)
Dim b As Boolean
Using modDef As ModuleDefMD = ModuleDefMD.Load("C:\Temp\ConsoleApplication1.exe")
For Each t As TypeDef In modDef.GetTypes
' stupid way to drill, but will work for demo purposes
If t.Name.Equals(typeName) Then
For Each m As MethodDef In t.Methods
b = m.HasBody
methods.Add(m)
Next
Exit For
End If
Next
End Using
Return methods
这或多或少就是Tmp对象所做的。你称之为丑陋,但由于源代码是一个懒人列表,它要么是丑陋的,要么就是通过
modDef
引用解决问题。当你得到异常时,什么对象是空的?@usr“HasBody”和“Body.Instructions”属性,但我确实使用了很多我没有验证是否为空的属性(不应为空)。如果可以,请查看我的问题更新,谢谢您的评论。将返回类型设置为“LazyList(Of MethodDef)”'没有解决问题。您还说,之所以涉及懒人,唯一的原因是因为我,但不是,我真的不想使用懒人,但如果我在函数中得到tu返回的数据类型,它就是一个懒人列表,如上面的代码所示(t.Methods.GetType.Name)。所有评论均未解决问题,请查看我的问题更新,我在其中发布了有助于更好理解问题的代码,感谢您的回答两次编辑…您不能
Private Function Test_Handler(typeName As String) As List(Of MethodDef)
Dim modDef As ModuleDefMD = ModuleDefMD.Load("C:\Temp\ConsoleApplication1.exe")
Dim methods As New List(Of MethodDef)
For Each t As TypeDef In modDef.GetTypes
' stupid way to drill, but will work for demo purposes
If t.Name.Equals(typeName) Then
'methods = t.Methods
methods.AddRange(t.Methods.ToArray)
Exit For
End If
Next
Return methods
End Function
Using ass As ModuleDefMD = ModuleDefMD.Load(Assembly)
Dim methods As New List(Of MethodDef)
Dim b As Boolean
Using modDef As ModuleDefMD = ModuleDefMD.Load("C:\Temp\ConsoleApplication1.exe")
For Each t As TypeDef In modDef.GetTypes
' stupid way to drill, but will work for demo purposes
If t.Name.Equals(typeName) Then
For Each m As MethodDef In t.Methods
b = m.HasBody
methods.Add(m)
Next
Exit For
End If
Next
End Using
Return methods