C# 如何在匿名方法中断开WinDbg?
标题说明了一切。通常的SOS命令!bpmd没有名字就没有什么好处 我有一些想法:C# 如何在匿名方法中断开WinDbg?,c#,debugging,windbg,anonymous-methods,sos,C#,Debugging,Windbg,Anonymous Methods,Sos,标题说明了一切。通常的SOS命令!bpmd没有名字就没有什么好处 我有一些想法: 转储所有方法,然后使用!bpmd-md当您找到相应的MethodDesc时 据我所知,在现实世界中并不实用。即使我编写了一个宏来将转储限制为匿名类型/方法,也没有明显的方法来区分它们 使用Reflector转储MSIL名称 在处理动态程序集和/或Reflection.Emit时没有帮助。Visual Studio无法读取此类场景中的本地变量,这就是我首先转向Windbg的全部原因 在VS中设置断点,等待它
- 转储所有方法,然后使用!bpmd-md当您找到相应的MethodDesc时
- 据我所知,在现实世界中并不实用。即使我编写了一个宏来将转储限制为匿名类型/方法,也没有明显的方法来区分它们
- 使用Reflector转储MSIL名称
- 在处理动态程序集和/或Reflection.Emit时没有帮助。Visual Studio无法读取此类场景中的本地变量,这就是我首先转向Windbg的全部原因
- 在VS中设置断点,等待它命中,然后
- 尝试从VS分离会导致其挂起(与应用程序一起挂起)。我认为这是因为托管调试器是一个标准调试器,而不是一个标准的“硬”调试器。或者它只是Silverlight特有的一个VS bug(可能不是第一个)
- 在其他已知的位置设置断点以调用匿名方法,然后单步执行
- 我的备份计划,但如果这个问答揭示了一个更好的方法,我宁愿不求助于它
- 匿名方法并不是真正的匿名方法。它只是隐藏在编译器生成的名称后面
考虑这个小例子:
Func<int, int> a = (x) => x + 1;
Console.WriteLine(a.Invoke(1));
通过MethodDesc,我们可以为Main()
0:000>!dumpil 00163010
ilAddr=003f2068
IL_0000:没有
IL_0001:ldstr“按回车键”
IL_0006:呼叫系统控制台::WriteLine
没有
IL_000c:呼叫系统控制台::ReadLine
IL_0011:流行音乐
IL_0012:ldsfld TestBench.Program::CS$9_ucachedanonymousmethoddelegate1
IL_0017:brtrue.s IL_002c
IL_0019:ldnull
IL_001a:ldftn测试台。程序::b_u0
IL_0020:newobj类[System.Core]System.Func`2::.ctor
IL_0025:stsfld TestBench.Program::CS$9_ucachedanonymousmethoddelegate1
IL_002a:br.s IL_002c
IL_002c:ldsfld测试台。程序::CS$9_缓存匿名方法delegate1
IL_0031:stloc.0
IL_0032:ldloc.0
IL_0033:ldc.i4.1
IL_0034:callvirt类[System.Core]System.Func`2::Invoke
IL_0039:呼叫系统控制台::WriteLine
IL_003e:没有
IL_003f:ret
注意那些有趣的名字。它们是生成委托类型和实际方法的名称。该方法称为b_uu0
。让我们看看这个方法:
0:000> !name2ee * TestBench.Program.<Main>b__0
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00152c5c (TestBench.exe)
Token: 0x06000003
MethodDesc: 00153024
Name: TestBench.Program.<Main>b__0(Int32)
Not JITTED yet. Use !bpmd -md 00153024 to break on run.
0:000>!名称2ee*TestBench.Program.b_u\u 0
模块:6db11000(mscorlib.dll)
--------------------------------------
模块:00152c5c(TestBench.exe)
令牌:0x06000003
方法描述:00153024
名称:TestBench.Program.b___0(Int32)
还没有紧张。使用!bpmd-md 00153024在运行时中断。
给你。MethodDesc是00153024,正如评论所说,您可以使用!bpmd使用MethodDesc设置断点 如果在您的场景中查找“…”名称很棘手,那么将其作为常规方法如何?这通常非常简单;唯一棘手的事情是捕获变量,但这并不太糟糕——例如,这些变量做同样的事情:
static void Main()
{
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
int div = 2;
foreach (var item in list.Where(x => x % div == 0))
{
Console.WriteLine(item);
}
ListSearcher ls = new ListSearcher();
ls.div = 2;
foreach (var item in list.Where(ls.Test))
{
Console.WriteLine(item);
}
}
class ListSearcher
{
public int div;
public bool Test(int x)
{
return x % div == 0;
}
}
static void Main()
{
列表=新列表{1,2,3,4,5};
int div=2;
foreach(列表中的变量项,其中(x=>x%div==0))
{
控制台写入线(项目);
}
ListSearcher ls=新ListSearcher();
ls.div=2;
foreach(列表中的var项目,其中(ls.测试))
{
控制台写入线(项目);
}
}
类列表搜索器
{
公共情报处;
公共布尔测试(int x)
{
返回x%div==0;
}
}
转储操作指向的方法描述符。方向。Nota bene:我意外发现WinDbg不必要了。如果您在动态程序集创建期间以编程方式发出DebuggableAttribute(),您将能够在VisualStudio中很好地看到本地变量。
0:000> !name2ee * TestBench.Program.<Main>b__0
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00152c5c (TestBench.exe)
Token: 0x06000003
MethodDesc: 00153024
Name: TestBench.Program.<Main>b__0(Int32)
Not JITTED yet. Use !bpmd -md 00153024 to break on run.
static void Main()
{
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
int div = 2;
foreach (var item in list.Where(x => x % div == 0))
{
Console.WriteLine(item);
}
ListSearcher ls = new ListSearcher();
ls.div = 2;
foreach (var item in list.Where(ls.Test))
{
Console.WriteLine(item);
}
}
class ListSearcher
{
public int div;
public bool Test(int x)
{
return x % div == 0;
}
}