跟踪静态构造函数执行

时间:2011-02-01 19:49:57

标签: c# .net debugging static-constructor

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

遗憾的是,我对静态构造函数没有很多控制权,不要问我为什么要依赖DI / IoC进行设置,但确实如此。

在我的应用程序中,在我的IoC准备就绪之前,没有任何东西应该引用此类静态或其他方式,但静态构造函数仍在执行。

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

5 个答案:

答案 0 :(得分:15)

一如既往,请使用:

Debugger.Break()

答案 1 :(得分:2)

这可以使用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. 使用.load sosex
  3. 加载sosex
  4. 下一步发出命令!mbm *Code.Test..cctor*
  5. 调试器在调用时中断 静态构造函数,之后您可以发出!mk来获取 调用堆栈
  6. 以下是!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
    

    HTH

答案 2 :(得分:1)

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

选中此link

  

静态构造函数具有以下

     
    

属性:

         

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

         

无法调用静态构造函数     直接

         

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

  

答案 3 :(得分: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
                }
            }
        }
    }
}

答案 4 :(得分:0)

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

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

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

This image shows how your editor with breakpoints would look like