gpt4 book ai didi

c# - .NET 反射来识别属性关系

转载 作者:太空宇宙 更新时间:2023-11-03 20:08:49 29 4
gpt4 key购买 nike

假设我有下面的类:

public class Car
{
public Car()
{

}
}

public class Motor
{
public Motor()
{

}
}

public class Vehicle
{
public Vehicle()
{
SuperCar = new Car();
}

public Car SuperCar { get; set; }
public string TestName { get; set; }
}

让我们看看下面的代码:

 Vehicle vehicle = new Vehicle();
Car superCar = vehicle.SuperCar;

现在,如果我们只给出 Car 实例,它是 superCar,是否可以从反射中知道 superCar 实例实际上属于 Vehicle 的属性之一?

好的。感谢您的意见。我认为通过反射是可能的。

因此,如果我们扩展代码:

PropertyInfo[] props = vehicle.GetType().GetProperties();

前提是,我们只给出:

PropertyInfo propInfo = props[0];

我们可以通过MemberInfo知道这个propInfo到底属于哪个类:

Console.WriteLine(((System.Reflection.MemberInfo)(propInfo)).DeclaringType.Name);

It would return Vehicle.

谢谢!

最佳答案

简答

不,这是不可能的。反射是一种读取程序集和其中类型的静态元数据 的方法。有关类型属性的信息是此类元数据的示例。但是诸如“哪些对象正在引用某个对象”之类的信息不是静态元数据。它是一个运行时数据,通常无法在 .NET 中访问。另一件事是,它真的没有必要。总是有更好的方法来设计东西(比如指向其 parent 的引用)。换句话说,您真的永远都不需要这样做,所以最好记住这是不可能的。

长答案

综上所述,我想指出的是,在惊人的 Microsoft.Diagnostics.Runtime 的帮助下,你想做什么是可能的图书馆。正如作者所说:

ClrMD is a set of advanced APIs for programmatically inspecting a crash dump of a .NET program much in the same way as the SOS Debugging Extensions (SOS). It allows you to write automated crash analysis for your applications and automate many common debugger tasks.

其实平时工作的时候也可以附加到自己的进程,分析一下。下面的代码非常 hacky,可能永远不应该使用,但它有效并展示了 .NET 世界的强大之处:

public bool IsReferencedByAnyVehicle(Car car)
{
ulong ptr;
// Nasty way of getting address
unsafe
{
TypedReference tr = __makeref(car);
ptr = (ulong)(**(IntPtr**)(&tr));
Console.WriteLine(ptr);
}

// Attach to the process itself, hence only AttachFlag.Passive flag is possible
var process = Process.GetCurrentProcess();
using (var dataTarget = DataTarget.AttachToProcess(process.Id, 250, AttachFlag.Passive))
{
string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
ClrRuntime runtime = dataTarget.CreateRuntime(dacLocation);

ClrHeap heap = runtime.GetHeap();
// Get all Vehicle objects from heap that has reference to ptr
var refs = heap.EnumerateObjects()
.Select(obj => new
{
Type = heap.GetObjectType(obj),
ObjectAddress = obj
})
.Where(t => t.Type != null &&
t.Type.Name.EndsWith("Vehicle") &&
GetReferences(t.Type, t.ObjectAddress).Contains(ptr))
.Any();
// Cleanup
runtime.Flush();
return refs;
}
}

public List<ulong> GetReferences(ClrType type, ulong objRef)
{
var result = new List<ulong>();
type.EnumerateRefsOfObjectCarefully(objRef, (addr, _) => result.Add(addr));
return result;
}

然后进行简单测试:

Vehicle vehicle = new Vehicle();
Car superCar = vehicle.SuperCar;
Car localCar = new Car();

bool isSuperCar = IsReferencedByAnyVehicle(superCar); // true
bool isLocalCar = IsReferencedByAnyVehicle(localCar); // false

注意:对于附加到自身,只有 AttachFlag.Passive 是可能的,描述为:

Performs a "passive" attach, meaning no debugger is actually attached to the target process. The process is not paused, so queries for quickly changing data (such as the contents of the GC heap or callstacks) will be highly inconsistent** unless the user pauses the process through other means.

因此结果可能并不总是确定性的。

关于c# - .NET 反射来识别属性关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21314697/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com