7

我在这里遇到了一个问题,我的一个类的静态构造函数在它应该被调用之前被调用。(即,DI/IoC 未设置,它正在从服务定位器返回空值/异常)。

不幸的是,我对静态构造函数没有太多控制权,不要问我为什么要设置 DI/IoC,但确实如此。

在我的应用程序中,在我的 IoC 准备就绪之前,不应引用此类静态或其他方式,但静态构造函数无论如何都会执行。

有没有一种简单的方法来确定是哪一行导致构造函数执行?注意:我不能在 中设置断点,static constructor因为这一切都发生在 ASP.NET 的远程调试器可以附加到 Web 服务器之前(在 Global.asax.cs 中)

4

5 回答 5

19

与往常一样,使用:

Debugger.Break()
于 2011-02-01T19:52:49.493 回答
3

这可以使用 Windbg 和 sosex 来完成。这是示例代码

using System;
namespace Code
{
class Test
{
  public static int i;
  static Test()
  {
    i = 10;
    Console.WriteLine(i);
  }
  static void Main()
  {
    Console.WriteLine(Test.i);
    Console.Read();
  }
}
}

这是步骤

  1. 将进程附加到windbg
  2. 使用加载 sosex.load sosex
  3. 接下来发出命令!mbm *Code.Test..cctor*
  4. 调试器在调用静态构造函数时中断,之后您可以发出!mk获取调用堆栈

这是!mk上述示例的输出

0:000> !mk
Thread 0:
     ESP              EIP
00:M 000000000026def8 000007ff00150120 Code.Test..cctor()(+0x0 IL)(+0x0 Native)
01:U 000000000026df00 000007fef43a10b4 clr!CallDescrWorker+0x84
02:U 000000000026df40 000007fef43a11c9 clr!CallDescrWorkerWithHandler+0xa9
03:U 000000000026dfc0 000007fef43a32b4 clr!DispatchCallDebuggerWrapper+0x74
04:U 000000000026e060 000007fef43aafdf clr!MethodTable::RunClassInitEx+0x1ff
05:U 000000000026e1b0 000007fef43aaca8 clr!MethodTable::DoRunClassInitThrowing+0x55e
06:U 000000000026ec70 000007fef43a3470 clr!MethodTable::CheckRunClassInitThrowing+0xe3
07:U 000000000026eca0 000007fef44cb848 clr!MethodDesc::DoPrestub+0x587
08:U 000000000026edb0 000007fef43a23f3 clr!PreStubWorker+0x1df
09:U 000000000026ee70 000007fef4362d07 clr!ThePreStubAMD64+0x87
0a:U 000000000026ef40 000007fef43a10b4 clr!CallDescrWorker+0x84
0b:U 000000000026ef80 000007fef43a11c9 clr!CallDescrWorkerWithHandler+0xa9
0c:U 000000000026f000 000007fef43a1245 clr!MethodDesc::CallDescr+0x2a1
0d:U 000000000026f230 000007fef44a1675 clr!ClassLoader::RunMain+0x228
0e:U 000000000026f480 000007fef44a17ac clr!Assembly::ExecuteMainMethod+0xac
0f:U 000000000026f730 000007fef44a1562 clr!SystemDomain::ExecuteMainMethod+0x452
10:U 000000000026fce0 000007fef44a3dd6 clr!ExecuteEXE+0x43
11:U 000000000026fd40 000007fef44a3cf3 clr!CorExeMainInternal+0xc4
12:U 000000000026fdb0 000007fef4527365 clr!CorExeMain+0x15
13:U 000000000026fdf0 000007fef6883309 mscoreei!CorExeMain+0x41
14:U 000000000026fe20 000007fef6915b21 MSCOREE!CorExeMain_Exported+0x57
15:U 000000000026fe50 0000000077a6f56d KERNEL32!BaseThreadInitThunk+0xd
16:U 000000000026fe80 0000000077ba3021 ntdll!RtlUserThreadStart+0x1d

高温高压

于 2011-02-01T20:15:13.173 回答
2

下面是我的静态构造函数调试经验,

当我试图通过在静态字段引用的行上放置一个断点来进行调试时,我没有获得对静态构造函数的调试控制。

我在静态构造函数入口处保留断点,从静态字段引用的行中删除断点。现在 Debug 控件开始进入静态构造函数代码。

此图显示了带有断点的编辑器的外观

于 2020-02-28T09:27:43.510 回答
1

您无法控制何时执行静态构造函数。将您正在执行的任何操作从构造函数移至静态Initialize()函数。只要你准备好了就打电话给那个。不要依赖于何时执行静态构造函数。

检查此链接

静态构造函数有以下

特性:

在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。

不能直接调用静态构造函数。

用户无法控制何时在程序中执行静态构造函数。

于 2011-02-01T19:53:30.213 回答
0

也许您应该跳过使用静态构造函数?有必要吗?

public class SomeClass
{
    private static bool IsInizialized = false;

    public SomeClass()
    {
        if (!IsInizialized)
        {
            // static constuctor thread safe but this doesn't
            //
            lock (this)
            {
                if (!IsInizialized)
                {
                    IsInizialized = true;
                    // all what static constructor does
                }
            }
        }
    }
}
于 2011-02-01T20:46:54.357 回答