26

当你创建一个应用程序时,你会在文件中WinForm获得一个自动生成的Program类模板。Program.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());
    }
}

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

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

4

5 回答 5

27

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

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

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

于 2013-09-30T11:33:21.997 回答
11

我的问题是,为什么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()签名可能会发生变化,但这种模板应该可以完成您正在寻找的内容。

谢谢阅读。

于 2015-12-23T16:17:16.290 回答
7

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

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

当然还有其他很好的理由来修改项目模板代码。例如,它将 Form 派生类的 Dispose() 方法放在 Designer.cs 文件中。不是一个好地方,“从不修改设计器生成的代码”规则确实让 Winforms 程序员瘫痪。将该方法移动到 Form.cs 文件中,然后对其进行修改就可以了。

这仅仅是“最有可能落入成功坑”的代码。毫不犹豫地改变它。

于 2013-09-30T12:00:49.217 回答
1

它之所以是静态的,是因为它只有静态方法,没有别的。如果您现在要添加接口、基类和非静态方法/属性/成员,则必须创建该类的实例才能使用它们(由于static class. 这仍然很好,甚至可以在静态 Main 方法中完成,但它可能会产生误导或不是该类的预期目的。我会创建一个 MyApplication 类,在静态 Main 中实例化它并从那里创建我的 Form。

关于您的异常处理程序。您仍然可以创建一个为您执行此操作的管理器类,您只需从 Main 调用它即可在所有程序中重用它。

于 2013-09-30T10:58:51.957 回答
0

main 方法在内存中只有一个实例,每个 C# 应用程序都有一个入口点。

于 2022-02-14T20:19:38.813 回答