为什么类“程序”被声明为静态
本文关键字:声明 静态 程序 为什么 | 更新日期: 2023-09-27 18:33:22
当您创建WinForm
应用程序时,您会在Program.cs
文件中获得Program
类的自动生成模板。
看起来像这样:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
我的问题是,为什么Program
类被声明为static
?
如果我删除static
声明,它仍然可以正常工作。
提出这个问题的原因是,我认为Program
从基类继承可能会很好,该基类将实现 Application.ThreadException 和 AppDomain.CurrentDomain.UnhandledException 的处理,而不是为我的所有项目实现或多或少相同的它。
它只遵循设计准则,即仅包含static
方法的类应标记为static
。更多信息可以在这里找到。
正如您已经注意到的那样,使您的Program
类不是静态的没有问题,唯一需要的是将static Main
方法作为入口点。您可以将实例方法添加到 Program
类,实例化它并像任何其他类一样使用。然而,这不是一个明确的方法,因为这违反了单一责任原则。 Program
的职责是为应用程序提供一个入口点,因此它不应该再做任何事情了。对于此任务,它只需要一个名为 Main
的static
方法。由于它仅包含static
方法,因此应将其标记为static
以符合 C# 编码准则。
一般来说,知道一个类是static
的很方便,所以你乍一看就知道它只包含static
方法。这是一种非常易读的方式来表达应该如何使用一个类。在这个例子中,它不是很重要,因为没有人明确使用Program
,但是为了严格起见,它应该是static
的。
我的问题是,为什么
Program
类被声明为static
?
正如您所指出的,它不必如此。 事实上,在我的Visual Studio版本(Visual Studio 2015 Enterprise Update 1(中,"控制台应用程序"的默认程序是
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
}
}
}
但是等等,为什么Main
又是静止的?
这个答案很好地解释了为什么Main
必须是静态的。 简而言之,答案指出Main
必须是静态的,因为另一种方法是 CLR 必须在 Program
上调用构造函数才能调用Program.Main
。 但是想想看,在入口点之前什么都没有发生,所以不能调用这样的构造函数!
提出这个问题的原因是,我认为
Program
从基类继承可能会很好,该基类将实现Application.ThreadException
和AppDomain.CurrentDomain.UnhandledException
的处理,而不是为我的所有项目实现或多或少相同的方法。
这是一个非常好的主意;DRY 是我最喜欢的编程原则之一。 但是,要以您的想法执行此操作,Program
需要从类型(例如ProgramBase
(的基本对象派生,并调用某种受保护的方法。也许是这样的东西?
internal class Program : ProgramBase
{
static void Main(string[] args)
{
// ERROR: "an object reference is required for the non-static
// field, method, or property ProgramBase.MainWrapper();"
MainWrapper();
}
protected override void DoMain()
{
// do something
}
}
internal abstract class ProgramBase
{
protected void MainWrapper()
{
try
{
// do some stuff
DoMain();
}
catch(...)
{
// handle some errors
}
}
protected abstract void DoMain();
}
问题出现了,要解决继承问题,Program.Main()
必须调用某种非静态方法。
好的,现在让我们用不同的方式解决问题。 让我们为不同类型的应用程序创建一个ApplicationBase
抽象类。
class Program
{
static void Main(string[] args)
{
var myApp = new MyApplication();
myApp.RunApp();
}
}
public class MyApplication : ApplicationBase
{
protected override void DoRunApp()
{
// do my stuff
}
}
public abstract class ApplicationBase
{
public void RunApp()
{
try
{
// create AppDomain, or some other construction stuff
// do some stuff
DoRunApp();
}
catch(...)
{
// handle some errors
}
catch(...)
{
// handle some other errors
}
}
protected abstract void DoRunApp();
}
现在我们正在到达某个地方。 根据您在设置/创建阶段创建的内容,您的DoRunApp()
签名可能会更改,但此类模板应该可以完成您要查找的内容。
感谢您的阅读。
避免过度思考。 这段代码只是从项目模板中出来,预先在 C:''Program Files (x86(''Microsoft Visual Studio 11.0''Common7''IDE''ProjectTemplates''CSharp''Windows''1033''WindowsApplication''Program 中预先准备好.cs
没有什么可以阻止您修改该代码,如果这是您喜欢的方式,删除 static 关键字是完全合理的。 它有一些逻辑,毕竟你只有一个程序,所以声明它是静态的确实是有意义的。 但将其与控制台模式应用的项目模板进行比较,它还声明了一个 Program 类,但没有将其设为静态。 对于控制台应用,使该类不是静态的根本没有额外的意义。
修改项目模板代码当然还有其他很好的理由。 例如,它将窗体派生类的 Dispose(( 方法放在 Designer.cs 文件中。 这不是一个好地方,"从不修改设计器生成的代码"规则确实让Winforms程序员瘫痪了。 将该方法移动到 Form.cs 文件中,然后对其进行修改就好了。
这只是"最有可能陷入成功的深渊"的代码。 毫不犹豫地改变它。
它是静态的原因是,因为它只有静态方法,没有其他方法。如果您现在要添加接口、基类和非静态方法/属性/成员,则必须创建该类的实例才能使用它们(由于static class
,这是禁止的(。这仍然很好,甚至可以在静态 Main 方法中完成,但它可能会产生误导或不是该类的预期目的。我会创建一个 MyApplication 类 anway,在静态 Main 中实例化它并从那里创建我的表单。
关于您的异常处理程序。您仍然可以创建一个为您执行此操作的管理器类,您只需从 Main 调用该类,即可在所有程序中重用。
内存中只有一个 main 方法的实例每个 C# 应用程序都有一个入口点。