为什么类"Program"声明为静态?

Avi*_*ner 16 c# static winforms

创建WinForm应用程序时,您将ProgramProgram.cs文件中获得自动生成的类模板.

看起来像这样:

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么这个Program类被声明为static
如果我删除static声明它仍然可以正常工作.

问题的原因是我认为Program从基类继承可能会很好,它将实现Application.ThreadExceptionAppDomain.CurrentDomain.UnhandledException的处理,而不是对我的所有项目实现或多或少相同.

Bar*_*zKP 16

它遵循设计准则,只包含static方法的类应标记为static.更多信息可以在这里找到.

使你的Program类不是静态没有问题,唯一需要的是static Main作为入口点的方法,正如你已经注意到的那样.您可以向Program类中添加实例方法,将其实例化并用作任何其他类.然而,这不是一个明确的方式,因为这违反了单一责任原则.Program我们的责任是为应用程序提供一个入口点,所以它不应该做更多的事情.对于此任务,它只需要一个static方法Main.由于它只包含static方法,因此应标记为static符合C#编码指南.

一般来说,知道一个类很方便static,所以你乍一看它只包含static方法.这是表达如何使用类的一种非常易读的方式.在这个例子中,它不是非常必要的,因为没有人Program明确使用,但是为了严格,它应该是static.


Fra*_*yce 7

我的问题是,为什么这个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)
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是等等,为什么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();
}
Run Code Online (Sandbox Code Playgroud)

出现的问题是,要解决继承问题,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();
}
Run Code Online (Sandbox Code Playgroud)

现在我们到了某个地方.根据您在设置/创建阶段创建的内容,您的DoRunApp()签名可能会更改,但此类模板应该可以完成您要查找的内容.

谢谢阅读.


Han*_*ant 5

避免过度思考这一点.此代码刚出自项目模板,预先在C:\ Program Files(x86)\ Microsoft Visual Studio 11.0\Common7\IDE\ProjectTemplates\CSharp\Windows\1033\WindowsApplication\Program.cs中编写

没有什么可以阻止你修改代码,删除静态关键字是完全合理的,如果这是你喜欢它的方式.它有一点逻辑,你毕竟只有一个程序,所以声明静态确实有意义.但是将它与Console模式应用程序的项目模板进行比较,它还声明了一个Program类但没有使它成为静态.对于控制台应用来说,使该类不是静态的,根本没有任何意义.

修改项目模板代码肯定还有其他充分的理由.例如,它将Surface派生类的Dispose()方法放在Designer.cs文件中.对它来说不是一个好地方,"永远不会修改设计器生成的代码"规则确实让Winforms程序员陷入瘫痪.将该方法移动到Form.cs文件中然后修改它就可以了.

这仅仅是"最有可能陷入成功的关键"代码.毫不犹豫地改变它.