【发布时间】:2021-07-28 17:10:55
【问题描述】:
在问题底部编辑
我的代码中有一个函数,它获取样本字典,从另一个工作簿填充数据并返回填充的字典。一切正常,但是一旦我将文件的打开方式更改为只读,我就会遇到问题。
这里是代码(已被简化以删除多余的部分):
Function get_samples_data(ByVal instructions As Scripting.Dictionary, ByRef patients_data As Scripting.Dictionary) As Scripting.Dictionary
'takes a dictionary of samples and fills their data from the file <0 GL all RL>
Dim wb As Workbook
Dim ws As Worksheet
Dim data_start As Long
Dim data_end As Long
Dim rw As Range
Dim rw_nr As String
'open <GP all> in ReadOnly mode based on path and filename in specific cells
Application.ScreenUpdating = False
Set wb = Workbooks.Open(ThisWorkbook.Sheets(1).Cells(13, 2).Value2 & ThisWorkbook.Sheets(1).Cells(13, 1).Value2, False, True)
Set ws = wb.Worksheets("ALL")
'get row nr. of the first and the last sample to export
data_start = ws.Columns("A:A").Find(what:=instructions("from_sample"), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows).Row
data_end = ws.Columns("A:A").Find(what:=instructions("to_sample"), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows).Row
'main loop
For i = data_start To data_end
Set rw = ws.Rows(i)
rw_nr = rw.Cells(1, 1).Value
If rw.Cells(1, 11).Value = instructions("group") Then
If patients_data.Exists(rw_nr) Then
Set patients_data(rw_nr) = fetch_sample_data(rw, patients_data(rw_nr))
End If
End If
Next
'close <GP all> without saving
wb.Close (False)
Set get_samples_data = patients_data
End Function
当我调试时,我注意到数据在调用 wb.Close(False) 时丢失了。直到该点数据完好无损,但一旦关闭源工作簿,数据(它是一个范围对象)就会变为空白。未设置为空,当在源工作簿中找不到数据时会发生这种情况,但在调试器中可以看到范围对象的所有属性,但所有属性的值都是 .
在我将 openmode 更改为 ReadOnly 之前,一切正常,数据保留在那里。 我错过了什么?为什么存储在不同变量中的数据会丢失?
编辑: 获取样本数据确实返回一个范围对象。
Private Function fetch_sample_data(ByVal rw As Range, ByRef sm As sample) As sample
Dim data As Range
Set data = Range(rw.Cells(1, 19), rw.Cells(1, 63))
Set sm.data = data
Set fetch_sample_data = sm
End Function
我尝试改变关闭顺序并设置返回值,但还是报错。
那么,Range 对象是否始终只是对工作表中某个范围的引用?如果我希望数据保留,是否需要将所有有问题的 Range 对象更改为数组?或者有没有办法创建一个独立于工作簿的 Range 对象(我不想将范围复制到带有宏的主工作簿中的任何工作表中)?
下面是主子,正如@Pᴇʜ 要求的那样。剩下的函数我就不加了,因为整个代码分散在 1 个表单、2 个模块和 14 个类上(很多都带有很长的方法)。 两个注释的打开命令是那些导致一切正常工作的命令。关闭命令位于 main sub 的末尾,因此关于@Pᴇʜ 的注释,如果 range 对象始终只是对实际单元格范围的引用,则它们在整个程序期间都可用。
Sub RL_creator_GP_main()
Dim instructions As New Scripting.Dictionary
Dim samples As Scripting.Dictionary
Dim result_list As Variant
Dim rep As cReport
Dim scribe As New descriptor
Application.ScreenUpdating = False
'get instructions from inputboxes (group, from sample, to sample)
Set instructions = procedures.input_instructions()
If instructions.Exists("terminated") Then
Exit Sub
End If
'get <GP all> and <RL headers> ready
'Call procedures.prepare_file("GP all.xlsx", pth:=ThisWorkbook.Sheets(1).Cells(12, 2).Value)
'Call procedures.prepare_file("RL headers.xlsx", pth:=ThisWorkbook.Sheets(1).Cells(13, 2).Value)
'get patients data from <RL headers>, closes the file afterwards
Set samples = procedures.get_patients_data(instructions)
'get patients data from <GP all>, closes the file afterwards
Set samples = procedures.get_samples_data(instructions, samples)
【问题讨论】:
-
只需更改顺序。首先
Set get_samples_data = patients_data然后用wb.Close (False)关闭工作簿 -
问题是你
Set rw = ws.Rows(i)所以变量rw被定义为Range,因此是对工作簿中范围的引用。所以这里最大的问题是fetch_sample_data返回什么?如果它返回一个 reference 到您关闭的工作簿中的某个范围,那么您将无法再访问该数据,因为工作簿已关闭。所以问题是您真的将数据存储在字典中还是对数据的引用? • 请在您的问题中包含fetch_sample_data的代码。 -
还有一个问题是为什么要返回函数
Set get_samples_data = patients_data中的数据?由于提供了ByRef,因此无论如何都会更改原始字典。所以不需要在函数中返回字典,而是应该把函数变成一个子函数。 • 请同时包含如何调用get_samples_data的代码部分。 -
OK 更新后,很明显您已将 references 放入字典中。因此,当您关闭这些引用所指向的工作簿时,将无法访问数据。字典没有数据,它只有可以找到的参考/地址。
-
@Pᴇʜ 所以是使用数组而不是 Range 对象的唯一解决方案,还是有其他明智的选择?