单元格()的默认属性 [英] The default property for cells()

查看:163
本文介绍了单元格()的默认属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的印象是 VBA 具有所有对象的默认属性。所以如果我说 Cells(counter,x)附加的默认属性将是 .value 。此外,我一直使用 Cells(counter,x) Cells(counter,x).value 可互换。但是,当通过for循环将项目添加到集合中时,我注意到,如果我没有包含 .value 而不是存储该值,则将其存储在该位置所表示的值在工作表中。这样,如果位置被删除,则集合中的引用将丢失。这带给我两个发现:1)集合可以存储非静态引用,并且2) Cells()和其他对象没有默认属性,例如 .value的



如果有人可以澄清,确认和启发,这将是非常好的。

解决方案

不,所有类型都不具有默认成员。



任何类模块都可以有一个默认成员,通过指定一个特殊的成员属性(您必须手动导出和编辑代码文件才能执行此操作,VBE不会公开任何功能):

 属性{member name} .VB_UserMemId = 0 

只允许一个成员一个类型的默认成员。






你发现了默认成员的肮脏,为什么要避免这种情况。 >

VBA做了很多事情来让我们的生活更轻松(例如隐式类型转换),默认成员就是其中之一。


集合可以存储非静态引用


我不知道什么静态参考erence是,但是当您在集合中存储对象引用时,您不存储对象的副本,而是存储参考


Cells()和其他对象没有默认属性,如 .value


Global.Cells 是一个参数化属性getter,返回一个 Range 对象引用; Range.Cells 也是一个getter,返回一个 Range 对象;在Excel对象模型中没有单元格类。 Range 的默认成员是其。但是当你这样做:

  Dim c As Collection 
Set c = New Collection
c。添加ActiveSheet.Cells(1,1)

然后你要添加范围引用 .Cells(1,1)返回,然后是:

  Debug.Print c.Item(1)

将输出 Range 对象的值。但是这样:

  Debug.Print TypeName(c.Item(1))

将输出范围



混乱?是。这就是为什么你应该始终指定 Option Explicit ,尽可能使用显式类型声明的变量,避免隐式类型转换,避免使用默认成员。



通过编写正确读取的代码,您可以避免一些VBA陷阱,当您最终想要学习一些VB.NET或C#时,不要迷失类型的安全性和明确性。






使用最新的Rubberduck build (一个我所管理的开源VBE加载项目),您可以指定一个类'默认成员一个特殊的注释(注释):

 '@ DefaultMember 
公共属性Get Foo
结束属性

注释触发代码检查结果,警告关于缺少的相应属性;运行该检查结果快速修复同步注释/属性,Rubberduck导出模块,添加 VB_Attribute Foo.VB_UserMemId = 0 属性,并为您重新导入模块。



相反,如果一个成员有一个 VB_UserMemId = 0 属性,但没有相应的 @DefaultMember 注释,Rubberduck会生成关于缺少注释的检查结果警告,并提出一个快速修复程序,为您自动添加ot。



有更多的注释存在,但超出了这个答案的范围。浏览所有信息的 RD新闻博客文章。


I was under the impression VBA had default properties for all its objects. So that if I say Cells(counter, x) the default property attached will be .value. Additionally, I've always used Cells(counter, x) and Cells(counter, x).value interchangeably. However, when adding items to a collection via a for loop, I noticed if I did not include .value instead of storing the value, it stored the value as represented by the location in the worksheet. Such that if the location were deleted the reference in the collection would be lost. This brings me to two discoveries: 1) Collections can store non-static references, and 2) Cells() and other objects do not have default properties such as .value.

If anyone can clarify, confirm, and enlighten, that would be excellent.

解决方案

No, not all types have a default member.

Any class module can have a default member, by specifying a special member attribute (you'd have to export and edit the code file manually to do this, the VBE doesn't expose any functionality for this):

Attribute {member name}.VB_UserMemId = 0

Only one member is allowed to be a type's default member.


You're discovering the nastiness of default members and why they should be avoided.

VBA does a lot of things to "make our lives easier" (e.g. implicit type conversions), and default members is one of these things.

Collections can store non-static references

I don't know what a "static reference" is, but when you store an object reference in a Collection, you're not storing a copy of the object but a reference to it.

Cells() and other objects do not have default properties such as .value.

Global.Cells is a parameterized property getter that returns a Range object reference; Range.Cells is also a getter that returns a Range object; there is no Cell class in the Excel object model. The default member of a Range is its Value. But then when you do this:

Dim c As Collection
Set c = New Collection
c.Add ActiveSheet.Cells(1, 1)

Then you're adding the Range reference that .Cells(1, 1) returns, and then this:

Debug.Print c.Item(1)

Will output that Range object's value. Yet this:

Debug.Print TypeName(c.Item(1))

Will output Range.

Confusing? Yes. That's why you should always have Option Explicit specified, work with variables declared with an explicit type as much as possible, avoid implicit type conversions, ...and avoid using default members.

By writing code that reads exactly as it should behave, you avoid a number of VBA traps, and when you eventually want to learn some VB.NET or C# you won't be lost at all about type safety and explicitness.


With the latest Rubberduck build (an open-source VBE add-in project I manage), you can specify a class' default member with a special comment ("annotation"):

'@DefaultMember
Public Property Get Foo()
End Property

The annotation triggers a code inspection result that warns about the missing corresponding attribute; running that inspection result's quick-fix "synchronize annotations/attributes", Rubberduck exports the module, adds the VB_Attribute Foo.VB_UserMemId = 0 attribute, and re-imports the module for you.

Conversely, if a member has a VB_UserMemId = 0 attribute, but no corresponding @DefaultMember annotation, Rubberduck produces an inspection result warning about the missing annotation, and proposes a quick-fix to automatically add ot for you.

More annotations exist, but would be beyond the scope of this answer. Browse the RD News blog posts for all the info.

这篇关于单元格()的默认属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆