C# 查找类型';.net堆中的s实例数据
假设我有两门课Foo和Bar,如下所示C# 查找类型';.net堆中的s实例数据,c#,.net,clrmd,C#,.net,Clrmd,假设我有两门课Foo和Bar,如下所示 public class Foo { private Bar _bar; private string _whatever = "whatever"; public Foo() { _bar = new Bar(); } public Bar TheBar { get { return _bar;
public class Foo
{
private Bar _bar;
private string _whatever = "whatever";
public Foo()
{
_bar = new Bar();
}
public Bar TheBar
{
get
{
return _bar;
}
}
}
public class Bar
{
public string Name { get; set; }
}
我有一个应用程序连接到使用这些类的进程。我想在.NET堆中查看Foo类型的所有实例,并检查TheBar.Name属性或所有的_任何字段
.NET堆中存在的Foo实例。我可以找到类型,但我不确定如何获取实例并查看其属性。你知道怎么做吗
using (DataTarget target = DataTarget.AttachToProcess(processId, 30000))
{
string dacLocation = target.ClrVersions[0].TryGetDacLocation();
ClrRuntime runtime = target.CreateRuntime(dacLocation);
if (runtime != null)
{
ClrHeap heap = runtime.GetHeap();
foreach (ulong obj in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(obj);
if (type.Name.Compare("Foo") == 0 )
{
// I would like to see value of TheBar.Name property or _whatever field of all instances of Foo type in the heap. How can I do it?
}
}
}
}
我不知道是否有可能以这种方式查询堆。 但一个简单的解决方法是这样做:
public class Foo
{
public static List<WeakReference<Foo>> allInstances = new List<WeakReference<Foo>>();
public Foo()
{
allInstances.Add(new WeakReference<Foo>(this));
}
}
公共类Foo
{
public static List allInstances=new List();
公共食物(
{
添加(新的WeakReference(this));
}
}
请确保将其包装在WeakReference中,这样在进程结束之前,您的集合不会将它们保留在堆中。我认为您无法直接获取属性值,因为这需要您运行代码,而目标甚至可能不是进程,而是转储文件 您完全可以获得对象的字段及其值。ClrType有一个字段属性,您可以使用该属性在字段之间循环。然后可以为HasSimpleValue为true的字段调用GetFieldValue 一个简单的例子:
private static void PrintFieldsForType(ClrRuntime runtime, string targetType)
{
ClrHeap heap = runtime.GetHeap();
foreach (var ptr in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(ptr);
if (type.Name == targetType)
{
foreach(var field in type.Fields)
{
if (field.HasSimpleValue)
{
object value = field.GetFieldValue(ptr);
Console.WriteLine("{0} ({1}) = {2}", field.Name, field.Type.Name, value);
}
else
{
Console.WriteLine("{0} ({1})", field.Name, field.Type.Name);
}
}
}
}
}
因此,您可以查找一个包含“Name”、“_Name”或类似内容的字段。如果它是一个自动实现的属性,名称将类似于k\uu BackingField
您的场景稍微复杂一些,因为您希望进入另一个对象。为此,我们可以递归地检查字段。但是请注意,在一般情况下,您希望跟踪您访问过的对象,这样就不会无限期地递归
以下是一个更适合于此的示例:
private static void PrintFieldsForType(ClrRuntime runtime, TextWriter writer, string targetType)
{
ClrHeap heap = runtime.GetHeap();
foreach (var ptr in heap.EnumerateObjects())
{
ClrType type = heap.GetObjectType(ptr);
if (type.Name == targetType)
{
writer.WriteLine("{0}:", targetType);
PrintFields(type, writer, ptr, 0);
}
}
}
private static void PrintFields(ClrType type, TextWriter writer, ulong ptr, int indentLevel)
{
string indent = new string(' ', indentLevel * 4);
foreach (var field in type.Fields)
{
writer.Write(indent);
if (field.IsObjectReference() && field.Type.Name != "System.String")
{
writer.WriteLine("{0} ({1})", field.Name, field.Type.Name);
ulong nextPtr = (ulong)field.GetFieldValue(ptr);
PrintFields(field.Type, writer, nextPtr, indentLevel + 1);
}
else if (field.HasSimpleValue)
{
object value = field.GetFieldValue(ptr);
writer.WriteLine("{0} ({1}) = {2}", field.Name, field.Type.Name, value);
}
else
{
writer.WriteLine("{0} ({1})", field.Name, field.Type.Name);
}
}
}
以下是如何在LINQPad中使用:
你可能没有抓住我问题的重点。我认为这就是clrmd库的全部目的,检查运行时元素。好的,但是它似乎需要很多东西,可以很容易地自己完成。你可以得到字段,但我不认为你可以得到属性,因为这等于在附加的进程中调用一个方法。我不认为CLR MD给了您这样做的能力,因为目标甚至可能不是一个进程,而是一个转储文件。您能举个例子说明如何访问字段吗?我已更新我的问题,以显示与财产相关的数据或字段
var session = ClrMDSession.AttachToProcess(processId);
session.EnumerateClrObjects("*Foo").Dump(depth:3);