为什么在 VB.Net 中每个窗体都有一个默认实例,而在 C# 中没有?

Why is there a default instance of every form in VB.Net but not in C#?

提问人:Shekhar_Pro 提问时间:1/15/2011 最后编辑:Visual VincentShekhar_Pro 更新时间:6/6/2016 访问量:9008

问:

我只是好奇地想知道有 (Name) 属性,它表示 Form 类的名称。此属性在命名空间中用于唯一标识 Form 是其实例的类,对于 Visual Basic,则用于访问窗体的默认实例。

现在这个默认实例从何而来,为什么 C# 不能有与此等效的方法。

此外,例如,为了在 C# 中显示表单,我们执行如下操作:

// Only method
Form1 frm = new Form1();
frm.Show();

但是在 VB.Net 中,我们有两种方法可以做到这一点:

' First common method
Form1.Show()

' Second method
Dim frm As New Form1()
frm.Show()
  1. 我的问题来自第一种方法。这是什么,它是类的实例还是类本身?现在,正如我上面提到的,表单名称是 VB.Net 中的 Default 实例。但是我们也知道这是一个类,那么实例和类名的名称怎么可能相同呢? 如果是一个类,则没有名为 Show() 的 (Static\Shared) 方法。 那么这种方法从何而来呢?Form1Form1Form1Form1DesignerForm1

  2. 它们在生成的 IL 中有什么区别?

  3. 最后,为什么 C# 不能有这样的等价物呢?

C# vb.net WinForms

评论

2赞 Merlyn Morgan-Graham 1/15/2011
“它们在生成的 IL 中有什么区别”:下载并使用 .NET Reflector 自行了解。它非常有用,而且是免费的。
3赞 Thomas Levesque 6/10/2012
我不想在 C# 中使用这个“功能”......这只是一个技巧,可以隐藏您需要创建类的实例才能使用它的事实。这真的是一个可怕的主意!此外,它的文档记录非常少,并且具有意想不到和危险的副作用(例如,每个线程都有自己的“默认实例”)
0赞 Shekhar_Pro 6/11/2012
@ThomasLevesque我不想要那个功能..我只是想知道它是如何完成的,是否有可能。.:)

答:

30赞 Jon Skeet 1/15/2011 #1

基本上,VB 是在背后将大量代码添加到您的项目中。

查看正在发生的事情的最简单方法是构建一个最小的项目,然后使用 Reflector 查看它。我刚刚用VB创建了一个新的WinForms应用程序,并添加了这个类:

Public Class OtherClass    
    Public Sub Foo()
        Form1.Show()
    End Sub
End Class

当反编译为 C# 时,Foo 的编译代码如下所示:

public void Foo()
{
    MyProject.Forms.Form1.Show();
}

MyProject.Forms是生成的类中的属性,类型为 。当你开始深入研究时,你会看到相当多的生成代码。MyProjectMyForms

当然,C# 可以完成所有这些工作,但它通常没有在背后做很多事情的历史。它为匿名类型、迭代器块、lambda 表达式等构建了额外的方法和类型——但与 VB 在这里所做的方式并不完全相同。C# 生成的所有代码都与您编写的源代码相对应 - 只是巧妙地转换了。

当然,这两种方法都有争论。就我个人而言,我更喜欢 C# 方法,但这可能并不奇怪。我不明白为什么应该有一种方法可以访问表单的实例,就好像它是单例一样,但仅适用于表单......基本上,无论我使用的是 GUI 类还是其他任何东西,我都喜欢这种语言以相同的方式工作。

评论

0赞 Javed Akram 1/15/2011
Form1.Show() 生成错误'WindowsApplication2.Form1' cannot refer to itself through its default instance; use 'Me' instead.
4赞 Jon Skeet 1/15/2011
@Javed:那么大概你不是在不同的类中使用它,就像我在我的例子中一样。
0赞 Kiquenet 2/26/2019
MyProject.Forms 在运行时生成?
0赞 Jon Skeet 2/26/2019
@Kiquenet:不,它是在编译时生成的。
39赞 Hans Passant 1/15/2011 #2

这在 VS2005 附带的 VB.NET 版本中被添加回语言中。根据大众的需求,VB6 程序员很难看出类型和对该类型对象的引用之间的区别。代码段中的 Form1 与 frm。这是有历史的,VB 直到 VB4 才有类,而表单一直可以追溯到 VB1。否则,这对程序员来说是相当严重的,理解这种差异对于编写有效的面向对象代码非常重要。C# 没有这个很大一部分原因。

您也可以在 C# 中恢复它,尽管它不会那么干净,因为 C# 不允许像 VB.NET 那样向全局命名空间添加属性和方法。你可以在表单代码中添加一些胶水,如下所示:

public partial class Form2 : Form {
    [ThreadStatic] private static Form2 instance;

    public Form2() {
        InitializeComponent();
        instance = this;
    }

    public static Form2 Instance {
        get {
            if (instance == null) {
                instance = new Form2();
                instance.FormClosed += delegate { instance = null; };
            }
            return instance;
        }
    }
}

现在可以在代码中使用 Form2.Instance,就像在 VB.NET 中使用 Form2 一样。属性 getter 的 if 语句中的代码应该移动到它自己的私有方法中,以使其高效,为了清楚起见,我保留了这种方式。

顺便说一句,该代码段中的 [ThreadStatic] 属性使许多 VB.NET 程序员在彻底绝望中放弃了线程。当抽象是泄漏时的问题。你真的最好不要这样做。

评论

3赞 MarkJ 1/17/2011
将其添加到 VB.Net 中的一个重要原因是帮助将现有代码从 VB1-3 移植到 VB.Net,因为没有其他选择,因此将使用该功能。这就是为什么我很高兴它被添加的原因:我个人认为它不应该在新代码中使用。此外,尽管我支持此功能并且对 VB6 有一些经验,但我认为我个人在理解类型和对类型实例的引用之间的区别方面没有任何问题:)
2赞 Thomas Levesque 6/10/2012
所以基本上 VB.NET 语言被修改了,因为用户太笨了,无法理解OOP......我总是惊讶于这种语言在很多方面都存在缺陷,同时仍然具有与 C# 几乎相同的功能。
16赞 Alex Essilfie 9/3/2013
@ThomasLevesque:“太傻了,看不懂OOP”?不,我建议你停止这种想法。Hans Passant 的回答表明,在 VB4 之前,VB 中不存在类,因此需要 VB.NET 此功能,以简化从 VBX 到 VB.NET 的项目升级。如果您尝试过将任何重要的 VBX 应用程序升级到 VB.NET,您就会知道可能会遇到多少错误,并且您会喜欢任何减少开发人员工作量的“非标准”语言改编。是的,MarkJ 是对的,它不应该在新代码中使用,但 VB 开发人员绝对不傻,否则他们就不会出现。
1赞 Thomas Levesque 9/3/2013
@AlexEssilfie,我并不是说 VB.NET 用户太愚蠢了,我是说语言被设计得好像他们一样。我理解需要与旧代码兼容,但这应该是您显式启用的可选功能,当然不是新项目的默认功能。
5赞 Steve 11/4/2014
骇人听闻的罪行正在以崇高理想的名义发生。例如Option Strict Off