为了账号安全,请及时绑定邮箱和手机立即绑定

未调用 Main(string[] args) 方法

未调用 Main(string[] args) 方法

C#
萧十郎 2022-11-22 16:40:37

我正在使用 Visual Studio 2017。

每当我按下F5开始调试我的程序时,我注意到类Main(string[] args)内部的方法Program没有被调用,即使内部的字段Program已经初始化,如下面的屏幕截图所示:

http://img1.sycdn.imooc.com/637c8b3400015d1218140643.jpg

创建TcpClient实例并将其分配给相应的字段后,调试器永远不会命中我在Main(string[] args)方法上设置的断点。

可以肯定的是,我已将项目的启动对象设置为Program该类。那没有解决问题:

http://img1.sycdn.imooc.com/637c8b3f0001338908050293.jpg

我错过了什么?

编辑:

我已经Console.WriteLine("Entering Main method...")在我的Main方法中添加了,但是当我开始调试时它没有打印到控制台。

TcpClient在创建实例之后,几乎没有任何事情(或者更确切地说,没有立即可见的事情)发生——没有抛出异常;该程序不会自行终止;控制台保持空白。

编辑:

结果是构造函数内部发生了崩溃TcpClient


查看完整描述

3 回答

?
梵蒂冈之花

TA贡献1588条经验 获得超5个赞

请记住,TcpClient(string, int)构造函数会在此时打开一个新连接 ( doc ):

初始化 TcpClient 类的新实例并连接到指定主机上的指定端口。
...
此构造函数创建一个新的 TcpClient 并尝试对提供的主机名和端口号进行同步连接。

如果我复制/粘贴您的代码(插入我自己的RemoteServerIpAddressString),那么我会看到应用程序在尝试构建TcpClient. 如果我在那时中断调试器,我可以看到它卡在 中System.Net.Sockets.Socket.DoConnect,它正在尝试连接到远程机器。

一段时间后它放弃,抛出一个异常,然后抛出一个异常TypeInitializationException,这会破坏调试器。

这符合您的观察:

在创建 TcpClient 实例之后,几乎没有任何事情(或者更确切地说,没有任何事情立即可见)发生——没有抛出异常;该程序不会自行终止;控制台保持空白。

此时,TcpClient仍在尝试连接。在它成功之前,该类型永远不会被初始化,并且在这发生Main之前永远不会运行。如果你离开它的时间足够长,它可能会失败,就像我的一样。

如果我确定TcpClient正在连接到一个打开的端口,那么TcpClient构造函数会立即完成并Main运行。


在静态构造函数中做长时间运行的事情——尤其是与网络有关的事情——是一个非常糟糕的主意。CLR 需要在初始化一个类型时获取锁,这会阻止其他类型的初始化,并可能导致死锁。

您可能想要在方法TcpClient内部Main构造,或者将其构造为:

private static readonly TcpClient TcpClient = new TcpClient();

然后主要是:

TcpClient.Connect(...);


查看完整回答
反对 回复 2022-11-22
?
智慧大石

TA贡献1680条经验 获得超3个赞

本例中的静态字段初始值设定项(Program 类)不应包含可能抛出或超时的代码。

问题中突出显示的代码是静态字段初始值设定项。这将在第一次访问类型时运行,在任何静态方法甚至静态构造函数之前运行。如果初始值设定项或静态构造函数阻塞或抛出,应用程序将终止而不调用Main. 这意味着没有错误处理代码可用于捕获这些异常。

这种有保证的顺序使得在 C# 中实现简单的单例变得非常容易。由于执行顺序得到保证,因此不需要双重锁定。查看 Jon Skeet 关于Singleton implementation的文章:

public sealed class Singleton

{

    private static readonly Singleton instance = new Singleton();


    // Explicit static constructor to tell C# compiler

    // not to mark type as beforefieldinit

    static Singleton()    {    }

    private Singleton()   {    }


    public static Singleton Instance

    {

        get 

        {

            return instance;

        }

    }

}

这足以创建一个线程安全的单例


查看完整回答
反对 回复 2022-11-22
?
qq_笑_17

TA贡献1538条经验 获得超7个赞

我正在添加一个新的答案,因为我在隐藏类加载和其他初始化异常的更复杂的托管环境中遇到了类似的问题。


为了解决这个问题,我这样做了:


将我的Main方法重命名为Main2,因此它不会与下一个更改冲突。

创建了另一个 Program 类,这次是干净的,它调用Main2,如下所示:

class CleanProgram {


    static void Main(string[] args) {

        try {

            Program.Main2(args);

        } catch (Exception ex) {

            Console.WriteLine("{0}", ex);

        }

    }


}

上面的更改仅用于诊断目的!找到并解决问题后,可以撤消更改。


查看完整回答
反对 回复 2022-11-22
  • 3 回答
  • 0 关注
  • 10 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信