延迟初始化混乱
Lazy initialization confusion
场景
我正在尝试读取 .Net 托管资源文件(ResX 文件)中包含的资源。
我设计了这个简单的 class,它将为我提供 store/struct 资源集合:
Public Class Resource
Public Property Name As String
Public Property Data As Object
Public ReadOnly Property Type As Type
Get
Return Data.GetType
End Get
End Property
End Class
所以,通过这个函数我得到了资源:
Public Iterator Function GetResources() As IEnumerable(Of Resource)
' Read the ResX file.
Using resX As New Resources.ResXResourceSet(Me.filePath1)
' Get the resource enumerator.
Dim resXDictionay As IDictionaryEnumerator = resX.GetEnumerator()
' Iterate the resources.
Do While resXDictionay.MoveNext()
Yield New Resource With {.Name = CStr(resXDictionay.Key),
.Data = resXDictionay.Value}
Loop
End Using ' resX
End Function
访问资源的方法是通过 public 属性 这样的:
Public ReadOnly Property Resources As IEnumerable(Of Resource)
Get
Return GetResources()
End Get
End Property
问题
问题在于,例如 ResX 文件包含大文件大小的资源,然后当我像这样迭代文件时,应用程序的内存消耗会增加该文件大小(甚至更多):
Dim resX As New ResXManager(".\MyResources.resx"))
For Each res As ResXManager.Resource In resX.Resources
Debug.WriteLine(res.Name)
' Debug.WriteLine(res.Type.ToString)
' Debug.WriteLine(res.Data.ToString)
Next res
注意上面的代码中注释了res.Data
,根本不是used/read,但是当资源很大时会增加内存消耗,例如资源大小为50 mb然后在我使用上面的循环的那一刻,应用程序的内存增加了 50 多 mb。
为了避免这个问题,我记得我不太了解的 Lazy
类型,但它不应该初始化 res.Data
内容,因为我不需要 read/use它在上面的循环中,我是对的?
那么,我如何将上面的代码修改为 return 一个 Lazy
列表?
我试过这种方法,但我确实遗漏了一些东西:
Public ReadOnly Property Resources As Lazy(Of Resource)
Get
Return New Lazy(Of Resource)(Function() GetResources())
End Get
End Property
它会抛出有关转换的编译器错误,我理解它,但我认为 Lazy
是某种类似于 IEnumerable
:
的集合
Option Strict On disallows implicit conversions from
'System.Collections.Generic.IEnumerable(Of
WindowsApplication2.ResXManager.Resource)' to
'WindowsApplication2.ResXManager.Resource'
问题
我怎样才能以正确的方式做到这一点?
简而言之,我想获得 Resource.Data
的可访问引用,但我只想避免 reading/initializing 它的内容(这会增加内存消耗),直到我真的需要 access/use 属性。
希望你能理解我。
帮不了你太多(不是我的主要专业领域)。不过,我已经做了一些调查...我认为如果你使用 ResXResourceReader
,然后设置 UseResXDataNodes = True
喜欢这里 When using the ResXResourceReader how can tell if the resource is an embedded file or if it is an embedded string 那么你应该可以在不加载资源的情况下加载资源的描述。
然后你可以使用GetValue
方法延迟加载资源,像这样:
Dim rsxr As ResXResourceReader = New ResXResourceReader("Resource1.resx") With { .UseResXDataNodes = True }
For Each de As DictionaryEntry In rsxr
Dim node As ResXDataNode = CType(de.Value, ResXDataNode)
' And then, when you need it
Dim obj As Object = node.GetValue(DirectCast(Nothing, ITypeResolutionService))
Next
请注意,有两个 GetValue
方法,要将 Nothing
传递给其中一个,您必须 DirectCast
它。
现在...我已经在 VB.NET 中完成了一个几乎完整的示例:
Public Class Resource
Public Property Name As String
Public Property Node As ResXDataNode
Public ReadOnly Property Data As Object
Get
Return Node.GetValue(DirectCast(Nothing, ITypeResolutionService))
End Get
End Property
Public ReadOnly Property Type As Type
Get
If (Node.FileRef Is Nothing) Then
Return GetType(String)
End If
Return System.Type.GetType(Node.FileRef.TypeName)
End Get
End Property
End Class
Public Iterator Function GetResources() As IEnumerable(Of Resource)
' Read the ResX file.
Using rsxr As ResXResourceReader = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
For Each de As DictionaryEntry In rsxr
Yield New Resource With {.Name = DirectCast(de.Key, String),
.Node = DirectCast(de.Value, ResXDataNode)}
Next
End Using
End Function
像以前一样使用它。 Data
按需加载。 Type
是在不加载 Data
.
的情况下计算的
场景
我正在尝试读取 .Net 托管资源文件(ResX 文件)中包含的资源。
我设计了这个简单的 class,它将为我提供 store/struct 资源集合:
Public Class Resource
Public Property Name As String
Public Property Data As Object
Public ReadOnly Property Type As Type
Get
Return Data.GetType
End Get
End Property
End Class
所以,通过这个函数我得到了资源:
Public Iterator Function GetResources() As IEnumerable(Of Resource)
' Read the ResX file.
Using resX As New Resources.ResXResourceSet(Me.filePath1)
' Get the resource enumerator.
Dim resXDictionay As IDictionaryEnumerator = resX.GetEnumerator()
' Iterate the resources.
Do While resXDictionay.MoveNext()
Yield New Resource With {.Name = CStr(resXDictionay.Key),
.Data = resXDictionay.Value}
Loop
End Using ' resX
End Function
访问资源的方法是通过 public 属性 这样的:
Public ReadOnly Property Resources As IEnumerable(Of Resource)
Get
Return GetResources()
End Get
End Property
问题
问题在于,例如 ResX 文件包含大文件大小的资源,然后当我像这样迭代文件时,应用程序的内存消耗会增加该文件大小(甚至更多):
Dim resX As New ResXManager(".\MyResources.resx"))
For Each res As ResXManager.Resource In resX.Resources
Debug.WriteLine(res.Name)
' Debug.WriteLine(res.Type.ToString)
' Debug.WriteLine(res.Data.ToString)
Next res
注意上面的代码中注释了res.Data
,根本不是used/read,但是当资源很大时会增加内存消耗,例如资源大小为50 mb然后在我使用上面的循环的那一刻,应用程序的内存增加了 50 多 mb。
为了避免这个问题,我记得我不太了解的 Lazy
类型,但它不应该初始化 res.Data
内容,因为我不需要 read/use它在上面的循环中,我是对的?
那么,我如何将上面的代码修改为 return 一个 Lazy
列表?
我试过这种方法,但我确实遗漏了一些东西:
Public ReadOnly Property Resources As Lazy(Of Resource)
Get
Return New Lazy(Of Resource)(Function() GetResources())
End Get
End Property
它会抛出有关转换的编译器错误,我理解它,但我认为 Lazy
是某种类似于 IEnumerable
:
Option Strict On disallows implicit conversions from 'System.Collections.Generic.IEnumerable(Of WindowsApplication2.ResXManager.Resource)' to 'WindowsApplication2.ResXManager.Resource'
问题
我怎样才能以正确的方式做到这一点?
简而言之,我想获得 Resource.Data
的可访问引用,但我只想避免 reading/initializing 它的内容(这会增加内存消耗),直到我真的需要 access/use 属性。
希望你能理解我。
帮不了你太多(不是我的主要专业领域)。不过,我已经做了一些调查...我认为如果你使用 ResXResourceReader
,然后设置 UseResXDataNodes = True
喜欢这里 When using the ResXResourceReader how can tell if the resource is an embedded file or if it is an embedded string 那么你应该可以在不加载资源的情况下加载资源的描述。
然后你可以使用GetValue
方法延迟加载资源,像这样:
Dim rsxr As ResXResourceReader = New ResXResourceReader("Resource1.resx") With { .UseResXDataNodes = True }
For Each de As DictionaryEntry In rsxr
Dim node As ResXDataNode = CType(de.Value, ResXDataNode)
' And then, when you need it
Dim obj As Object = node.GetValue(DirectCast(Nothing, ITypeResolutionService))
Next
请注意,有两个 GetValue
方法,要将 Nothing
传递给其中一个,您必须 DirectCast
它。
现在...我已经在 VB.NET 中完成了一个几乎完整的示例:
Public Class Resource
Public Property Name As String
Public Property Node As ResXDataNode
Public ReadOnly Property Data As Object
Get
Return Node.GetValue(DirectCast(Nothing, ITypeResolutionService))
End Get
End Property
Public ReadOnly Property Type As Type
Get
If (Node.FileRef Is Nothing) Then
Return GetType(String)
End If
Return System.Type.GetType(Node.FileRef.TypeName)
End Get
End Property
End Class
Public Iterator Function GetResources() As IEnumerable(Of Resource)
' Read the ResX file.
Using rsxr As ResXResourceReader = New ResXResourceReader(Me.filePath1) With {.UseResXDataNodes = True}
For Each de As DictionaryEntry In rsxr
Yield New Resource With {.Name = DirectCast(de.Key, String),
.Node = DirectCast(de.Value, ResXDataNode)}
Next
End Using
End Function
像以前一样使用它。 Data
按需加载。 Type
是在不加载 Data
.