.text
、.value
和 .value2
有什么区别?比如说,在什么情况下应该使用 target.text、target.value 或 target.value2?
.text
、.value
和 .value2
有什么区别?比如说,在什么情况下应该使用 target.text、target.value 或 target.value2?
.Text
提供了一个代表单元格屏幕上显示的字符串。使用.Text
通常是不明智的,因为你可能会得到####
。
.Value2
给出了单元格的实际值(包括空值、字符串、错误、数字(双精度)或布尔值)。
.Value
与.Value2
相同,除非单元格被格式化为货币或日期,这将给你VBA货币(可能截断小数位)或VBA日期。
使用.Value
或.Text
通常是不明智的,因为你可能无法获得单元格的真实值,而且它们比.Value2
更慢。
有关更详细的讨论,请参见 Text vs Value vs Value2。
Format $(Range.Value2,Range.NumberFormat)
。 - ChrisBtarget.Value
将会返回一个Variant
类型。
target.Value2
也会返回一个Variant
类型,但是如果Date
被强制转换为Double
类型。
target.Text
试图强制转换为String
类型,如果底层的Variant
不能强制转换为String
类型,则会失败。
最安全的做法是像下面这样:
Dim v As Variant
v = target.Value 'but if you don't want to handle date types use Value2
在进行显式强制转换之前,使用VBA.VarType(v)
检查变量的类型。
关于C#中的约定。假设您正在读取一个包含日期的单元格,例如2014-10-22。
使用:
.Text
,您将获得格式化后的日期表示形式,就像在屏幕上查看的一样:
2014-10-22。此属性的类型始终为string
,但可能不总是返回令人满意的结果。
.Value
,编译器尝试将日期转换为DateTime
对象:{2014-10-22 00:00:00}。在读取日期时可能非常有用。
.Value2
,给出单元格的实际基础值。对于日期,它是一个日期序列:41934。该属性的类型可以根据单元格内容而异。然而,对于日期序列,类型为double
。
因此,您可以在dynamic
,var
或object
中检索和存储单元格的值,但请注意,该值将始终具有某种固有类型,您需要对其进行操作。
dynamic x = ws.get_Range("A1").Value2;
object y = ws.get_Range("A1").Value2;
var z = ws.get_Range("A1").Value2;
double d = ws.get_Range("A1").Value2; // Value of a serial is always a double
.Text是格式化单元格的显示值;.Value是可能附带日期或货币指示符的单元格的值;.Value2是剥离了任何多余信息的原始基础值。
range("A1") = Date
range("A1").numberformat = "yyyy-mm-dd"
debug.print range("A1").text
debug.print range("A1").value
debug.print range("A1").value2
'results from Immediate window
2018-06-14
6/14/2018
43265
range("A1") = "abc"
range("A1").numberformat = "_(_(_(@"
debug.print range("A1").text
debug.print range("A1").value
debug.print range("A1").value2
'results from Immediate window
abc
abc
abc
range("A1") = 12
range("A1").numberformat = "0 \m\m"
debug.print range("A1").text
debug.print range("A1").value
debug.print range("A1").value2
'results from Immediate window
12 mm
12
12
如果您正在处理单元格的值,则读取原始的.Value2比.Value或.Text略快。 如果您正在定位错误,则.Text将返回像#N/A
这样的文本,可以与字符串进行比较,而.Value和.Value2将无法将其返回值与字符串进行比较。 如果您对数据应用了一些自定义单元格格式,则在构建报告时使用.Text可能是更好的选择。
Value2
几乎总是在从 VBA 读取或写入 Excel 单元格或范围时的最佳选择。
Range.Value2 '<------Best way
v = [a1]
v = [a1].Value
v = [a1].Value2
v = [a1].Text
v = [a1].Formula
v = [a1].FormulaR1C1
[a1] = v
[a1].Value = v
[a1].Value2 = v
[a1].Formula = v
[a1].FormulaR1C1 = v
如果需要从大范围读取多个值,或者写入多个值,整体操作一次比逐个单元格操作快上几个数量级:
arr = [a1:z999].Value2
arr
是Variant类型的变量,上述行实际上创建了一个26列宽和999行高的变体OLE SAFEARRAY结构,并将Variant arr
指向内存中的SAFEARRAY结构。请注意保留HTML标签。[a1].Resize(UBound(arr), UBound(arr, 2).Value2 = arr
以上代码将整个数组一次性写入工作表中,无论数组有多大(只要它能适应工作表)。
范围对象的默认属性是Value
属性。因此,如果未为范围指定属性,则默认情况下会静默引用Value
属性。
但是,Value2
是访问范围值最快的属性,在读取时返回真实的底层单元格值。它忽略数字格式、日期、时间和货币,并将数字作为VBA双精度数据类型始终返回。由于Value2
试图做更少的工作,所以执行速度比Value
稍微快一些。
另一方面,Value
属性检查单元格值是否具有日期或时间的数字格式,并在这些情况下返回VBA日期数据类型的值。如果您的VBA代码将使用日期数据类型,那么使用Value
属性检索它们可能是有意义的。将VBA日期数据类型写入单元格将自动使用相应的日期或时间数字格式格式化单元格。将VBA货币数据类型写入单元格也将自动将货币数字格式应用于相应的单元格。
类似地,Value
检查单元格货币格式,然后返回VBA货币数据类型的值。这可能会导致精度损失,因为VBA货币数据类型仅识别四个小数位(因为VBA货币数据类型实际上只是一个64位整数,乘以10000)。因此,最多将值舍入到四个位置。而且奇怪的是,使用Value
将VBA货币变量写入工作表范围时,该精度仅缩减到两个小数位。
只读的Text
属性始终返回VBA字符串数据类型。由Range.Text
返回的值是每个单元格中显示的文本表示形式,包括数字格式、日期、时间、货币和错误文本。这不是将数字值传递到VBA的有效方法,需要隐式或显式强制转换。当列太窄时,Text
将返回#######,当调整某些行高度时,它将变得更慢。与Value
和Value2
相比,Text
始终非常慢。但是,由于Text
保留了单元格值的格式外观,因此Text
可能很有用,特别是用于使用正确格式化的文本值填充用户窗体控件。
Formula
和 FormulaR1C1
始终会返回 VBA 字符串数据类型的值。如果单元格包含公式,则 Formula
返回其 A1 样式表示法,FormulaR1C1
返回其 R1C1 表示法。如果单元格具有硬编码值而非公式,则 Formula
和 FormulaR1C1
忽略所有格式并返回真实的底层单元格值,就像 Value2
一样... 然后进一步将该值转换为字符串。同样地,这不是将数字值导入 VBA 的有效方式,因为需要隐式或显式强制转换。但是,必须使用 Formula
和 FormulaR1C1
来读取单元格公式。它们应该用于向单元格写入公式。MsgBox [a1].Value 'Displays: 100.25
MsgBox TypeName([a1].Value) 'Displays: Currency
MsgBox [a1].Value2 'Displays: 100.25
MsgBox TypeName([a1].Value2) 'Displays: Double
MsgBox [a1].Text 'Displays: $ 100.25
MsgBox TypeName([a1].Text) 'Displays: String
MsgBox [a1].Formula 'Displays: 100.25
MsgBox TypeName([a1].Formula) 'Displays: String
MsgBox [a1].FormulaR1C1 'Displays: 100.25
MsgBox TypeName([a1].FormulaR1C1) 'Displays: String
出于好奇,我想看看 Value
在与 Value2
相比时的表现。经过大约12次类似过程的试验后,我没有看到任何明显的速度差异,因此我始终建议使用 Value
。我使用下面的代码对各种范围进行了一些测试。
如果有人发现性能方面有任何不同的情况,请发布。
Sub Trial_RUN()
For t = 0 To 5
TestValueMethod (True)
TestValueMethod (False)
Next t
End Sub
Sub TestValueMethod(useValue2 As Boolean)
Dim beginTime As Date, aCell As Range, rngAddress As String, ResultsColumn As Long
ResultsColumn = 5
'have some values in your RngAddress. in my case i put =Rand() in the cells, and then set to values
rngAddress = "A2:A399999" 'I changed this around on my sets.
With ThisWorkbook.Sheets(1)
.Range(rngAddress).Offset(0, 1).ClearContents
beginTime = Now
For Each aCell In .Range(rngAddress).Cells
If useValue2 Then
aCell.Offset(0, 1).Value2 = aCell.Value2 + aCell.Offset(-1, 1).Value2
Else
aCell.Offset(0, 1).Value = aCell.Value + aCell.Offset(-1, 1).Value
End If
Next aCell
Dim Answer As String
If useValue2 Then Answer = " using Value2"
.Cells(Rows.Count, ResultsColumn).End(xlUp).Offset(1, 0) = DateDiff("S", beginTime, Now) & _
" seconds. For " & .Range(rngAddress).Cells.Count & " cells, at " & Now & Answer
End With
End Sub
.Value2
更快。 - Excel Hero