我试图读取.Net托管资源文件中包含的资源,即ResX文件。
我设计了这个简单的类,它将用于存储/构建资源集合:
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 ReadOnly Property Resources As IEnumerable(Of Resource)
Get
Return GetResources()
End Get
End Property
所有这一切的问题是,例如ResX文件包含BIG文件大小的资源,然后当我像这样迭代文件时,应用程序的内存消耗增加了该文件大小(以及更多):
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
中有注释,根本没有使用/读取,但是当资源很大时会增加内存消耗,例如,如果资源大小为50 mb,那么此刻我使用应用程序内存上方的循环增加了超过50 MB。
为了避免此问题,我记得Lazy
类型,我不太了解它但不应该初始化res.Data
内容,因为我不需要阅读/使用它在上面的循环中,我是对的吗?
然后,我如何调整上面的代码以返回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禁止隐式转换 ' System.Collections.Generic.IEnumerable(中 WindowsApplication2.ResXManager.Resource)'至 ' WindowsApplication2.ResXManager.Resource'
我怎么能以正确的方式做到这一点?。
简而言之,我希望有Resource.Data
的可访问引用,但我想避免读取/初始化其内容(增加内存消耗),直到我真正需要访问/使用该属性。
我希望你能理解我。
答案 0 :(得分:1)
无法帮助你(不是我的主要专业领域)..不过,我已经做了一些寻找...我认为如果你使用ResXResourceReader
,那么你像When using the ResXResourceReader how can tell if the resource is an embedded file or if it is an embedded string一样设置UseResXDataNodes = True
,那么您应该能够在不加载资源的情况下加载资源描述。
然后您可以使用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
。