为什么即使不是静态方法,我也可以调用Form.Close()方法?

5

有人能给我解释一下吗?

在Visual Studio 2010中,创建一个VB.net Windows窗体应用程序。添加两个窗体:Form1和Form2。在Form1 Load事件中键入Form2.Close()。现在,如果我们查看方法定义,Close()不是静态(共享)方法。那么这怎么可能编译或在运行时工作呢。

此外,在C#中做同样的事情,Form2.Close()无法编译。

发生了什么?为什么在VB.net中可以这样做,执行该行代码时实际上正在发生什么?


2
这就是当微软让MS Access开发人员负责VB.NET以使其更吸引VB6/VBA用户群时所发生的事情。灾难随之而来... - John Alexiou
@ja72 当然,任何被称为“VB.x”的东西的目的都是至少对VB6和VBA用户有一定吸引力。话虽如此,我讨厌VB6中的这个功能,它的延续是学习C#而不是VB的另一个原因,所以我想它只吸引了部分VB用户。 - Jon Hanna
3个回答

6
你发现了一种名为“默认实例”的VB.NET特性。
编译器实际上会生成以下内容:
My.Forms.Form2.Close();

这是一个关于该特性的好文章,链接在此:http://jmcilhinney.blogspot.com/2009/07/vbnet-default-form-instances.html
默认实例是VB应用程序框架为您创建和管理的该类型的对象。
如果您使用默认实例,则无需显式调用构造函数。您可以通过My.Forms对象直接访问默认实例。

3
我喜欢这个特性背后的原因:VB 的主要目标之一一直是在尽可能让尽可能多的人轻松编程的同时提供强大的功能。默认表单实例的引入是为了实现这个目标。许多新手在 VB.NET 中使用对象,但他们并没有真正理解它们。引入隐式惰性实例化单例模式是一个美好的理由:许多 OOP 新手不太了解 OOP,所以让我们引入另一个卓越的特性。 - vgru
在这种情况下到底发生了什么事情呢?我的客户几乎不理解自己在做什么,对面向对象编程的知识也非常匮乏。然而,他却成功地做到了完全相反的事情:当他试图减少程序使用的内存时,他却增加了它的内存使用量。 - Jonas Stawski

5

原因是如果您只按名称引用表单,VB将创建一个自动实例,如果未被捕获,在运行时可能会导致意外后果。

我没有找到任何设置来防止发生这种情况。

但是,您可以通过将默认构造函数的范围从Public更改为Friend或删除默认构造函数并添加需要参数的构造函数,在编译时“破坏”此行为。 这些更改中的任何一个都将禁用自动窗体引用。


1
您说得对,当Form2只是一个类类型时,您无法调用Form2.Close();。但是,在VB.NET中,它会在后台创建一个同名的属性,因此实际上您是在一个Form2实例上调用Close。如果您手动创建这样的属性,您也可以在C#中执行相同的操作。它看起来像静态方法调用,但实际上并不是静态方法。

1
这是编译器使用VB应用程序框架发出对默认实例的调用。 - vcsjones
使用ILSpy或类似工具查看可执行文件的生成部分。这是作为属性实现的。 - user743382
这是一个属性,那只是实现细节,说它是一个属性并不能解释它的工作原理。它是在一个编译器生成的类型 MyForms 上的一个属性。此外,VB.NET 并没有给出任何提示,表明您正在对一个属性调用 Close。它看起来像是一个静态调用。 - vcsjones
是的,除了我没有提到的编译器生成类型的名称之外,它是实现在上面的,这不就是我说的吗? - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接