为什么类“程序”被声明为静态

本文关键字:声明 静态 程序 为什么 | 更新日期: 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 的职责是为应用程序提供一个入口点,因此它不应该再做任何事情了。对于此任务,它只需要一个名为 Mainstatic方法。由于它仅包含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.ThreadExceptionAppDomain.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# 应用程序都有一个入口点。