我通常使用VBA但是已经阅读了 C#编程黄皮书中的编程技术,这显然更适用于C#。无论如何,它提到了一种使用Out
关键字传递参数的技术。
我已经知道VBA支持byVal
和byRef
并且相当确定Out
没有直接的等价物。使用Out
传递参数与通过Ref
传递参数略有不同。
这个答案https://stackoverflow.com/a/388781/3451115似乎很好地解释了Out
& Ref
。
Ref修饰符表示:
该值已设置 该方法可以读取和修改它。
Out修饰符表示:
值未设置,方法无法读取,直到设置为止。 该方法必须在返回之前设置它。
在我继承的代码库中,有几个地方使用接受参数byRef
的方法将值分配给变量。在我看来,虽然通过byRef
做了工作,但通过Out
会更安全......所以(这里是问题)是否有安全的方法/在VBA中可靠地复制Out
在我的第一次迭代中(原始问题)我想象代码会有如下模式:
Sub byOutExample(byRef foo As String)
' Check before running code:
' foo must = vbNullString
If foo <> vbNullString then Err.Raise(someError)
' Do Something to assign foo
foo = someString
' Check before exiting:
' foo must <> vbNullString
If foo = vbNullString then Err.Raise(someError)
End Sub
其他考虑因素:值得做,是否有更好的方法,可能出现什么问题?
修改: 我在上述Ref
vs Out
定义的评论中注意到,传递的参数不必是null
,{ {1}},nothing
等可以预先分配 - 主要标准似乎是重新分配。
根据@ ThunderFrame的回答以及empty
传递的参数可以预先指定(和使用)的评论,可能以下是更好的方法:
Out
在这种情况下,只要 Sub byOutExample(ByRef foo As String)
Dim barTemp As String
barTemp = foo
' Do Something to assign a new value to foo (via barTemp)
barTemp = someString
' Must assign new variable
foo = barTemp
End Sub
仅出现在上面显示的2个位置中,上述代码就是复制foo
传递参数的准确方法。 VBA?
答案 0 :(得分:1)
您可以通过在out
中传递ByRef
类型参数,然后在继续之前检查它是Nothing
(或值类型的默认值)来伪执行Nothing
类型参数就像你在你的例子中使用String一样。
我不会强加退出条件 - 有时空字符串是一个完全有效的返回值,就像ensembl <- useMart("ensembl")
ensembl <- useDataset("hsapiens_gene_ensembl",mart=ensembl)
getBM(attributes=c('chromosome_name', 'start_position', 'end_position', 'strand'),
filters=c('hgnc_symbol', 'ensembl_gene_id'),
values=list('TTN', 'ENSG00000155657'),
mart=ensembl)
引用一样。
答案 1 :(得分:1)
答案明确是“不”,你无法在VBA中复制C#out
参数修饰符。来自https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier:
作为out参数传递的变量不必在之前初始化 在方法调用中传递。但是,需要调用方法 在方法返回之前分配一个值。
这些方面在VBA中根本不存在。 VBA中的所有变量都使用默认值初始化,即VBA中不存在单元化变量的概念,因此第1点是不可能的;如果指定的参数没有在过程中分配值,则编译器无法对象,因此也不可能出现第2点。
即使您的示例中的编码模式依赖于Do Something to assign foo
也不会解析为相关数据类型的默认值(这显然与单元化不同)。例如,以下内容会错误地抛出错误:
Public Sub Main()
Dim income As Long, costs As Long
Dim result As Long
income = 1000
costs = 500
ProcessSpend income, costs, result
End Sub
Private Sub ProcessSpend(income As Long, costs As Long, ByRef outValue As Long)
Const TAX_RATE As Long = 2
Dim netCosts As Long
Dim vbDefaultValue As Long
netCosts = costs * TAX_RATE
outValue = income - netCosts
If outValue = vbDefaultValue Then Err.Raise 5, , "Unassigned value"
End Sub
所以我们真的还有这样一个问题:是否有办法接近VBA中out
的特征?
Variant
或Object
类型,默认情况下分别初始化为Empty
和Nothing
。这一切都倾向于帮助班:
Option Explicit
Private mNumber As Long
Private mTargetProc As LongPtr
Private mAssignedInProc As Boolean
Public Sub SetTargetProc(targetProc As LongPtr)
mTargetProc = targetProc
End Sub
Public Sub SetNumber(currentProc As LongPtr, val As Long)
mAssignedInProc = (currentProc = mTargetProc)
mNumber = val
End Sub
Public Property Get Number() As Long
If mAssignedInProc Then
Number = mNumber
Else
Err.Raise 5, , "Unassigned value"
End If
End Property
然后前面的例子看起来像这样:
Public Sub Main()
Dim income As Long, costs As Long
Dim result As clsOut
income = 1000
costs = 500
ProcessSpend income, costs, result
Debug.Print result.Number
End Sub
Private Sub ProcessSpend(income As Long, costs As Long, outValue As clsOut)
Const TAX_RATE As Long = 2
Dim netCosts As Long
If outValue Is Nothing Then
Set outValue = New clsOut
End If
outValue.SetTargetProc AddressOf ProcessSpend
netCosts = costs * TAX_RATE
outValue.SetNumber AddressOf ProcessSpend, income - netCosts
End Sub
但是这一切都变得非常繁重......而且我觉得好像我们试图将另一种语言的语法强加到VBA上。稍微退一步out
特征并开发VBA设计的语法,然后返回Variant
的函数似乎是最明显的方法。您可以通过检查函数是否返回Empty
变量(适合out
特征的第1点和第2点)来测试是否忘记设置'out'值:
Public Sub Main()
Dim income As Long, costs As Long
Dim result As Variant
income = 1000
costs = 500
result = ProcessedSpend(income, costs)
If IsEmpty(result) Then Err.Raise 5, , "Unassigned value"
End Sub
Private Function ProcessedSpend(income As Long, costs As Long) As Variant
Const TAX_RATE As Long = 2
Dim netCosts As Long
netCosts = costs * TAX_RATE
'Comment out the line below to throw the unassigned error
ProcessedSpend = income - netCosts
End Function
如果您想要传递预先指定的值,那么可以将可选参数定义为函数的参数。