简体   繁体   English

获取 object 调用层次结构

[英]Get object call hierarchy

Lets say I have 3 classes:假设我有 3 个课程:

class A {
   void do_A() {
      //Check object call hierarchy
    }
}
class B {
   void do_B() {
      A a;
      a.do_A();
    }
}
class C {
   void do_C() {
      B b;
      b.do_A();
    }
}

And then I call:然后我打电话:

C c;
c.do_C();

How can i get the object call hierarchy from within A's do_A()?如何从 A 的 do_A() 中获取 object 调用层次结构?

I mean I want to get the references of object in a.do_A() (can be easily attained by this ), the reference of object b that called a.do_A() , and the reference of object c that called b.do_B() . I mean I want to get the references of object in a.do_A() (can be easily attained by this ), the reference of object b that called a.do_A() , and the reference of object c that called b.do_B( ) .

I think this should be possible, because I can get the call hierarchy with call stack, so I'm sure I should be able to get some more information about the objects who called the methods.我认为这应该是可能的,因为我可以通过调用堆栈获得调用层次结构,所以我确信我应该能够获得有关调用方法的对象的更多信息。

First off, what you are describing is a bad programming practice.首先,您所描述的是一种糟糕的编程习惯。 A method's behaviour should depend upon its argument, not upon who called it .方法的行为应该取决于它的参数,而不是取决于谁调用它 A method should be reliable, so that you know that you get the same behaviour no matter who called it.一个方法应该是可靠的,这样你就知道无论谁调用它,你都会得到相同的行为。

Second, you seem to be of the common but false belief that the call stack is a real thing that tells you where the call came from .其次,您似乎普遍但错误地认为调用堆栈是一个真实的东西,它告诉您调用来自哪里 That is not at all the purpose of the call stack, though for debugging scenarios it sure is useful.这根本不是调用堆栈的目的,尽管对于调试场景它肯定是有用的。 The purpose of a call stack is to tell you where you are going next , not where you came from .调用堆栈的目的是告诉您下一步要去哪里,而不是从哪里来 Now, it is usually the case that where you are going next is also where you came from.现在,通常情况下,你接下来要去的地方也是你来自的地方。 The fact that often you can deduce where you came from based on knowing where you are going next is frequently useful, but you cannot rely upon it.您通常可以根据知道您接下来要去哪里来推断您来自哪里,这一事实通常很有用,但您不能依赖它。 The call stack is permitted to contain only enough information to determine where you are going next;调用堆栈允许包含足够的信息来确定下一步要去哪里; it can throw away every bit of information not necessary to determine where you are going next.它可以丢弃确定您下一步要去哪里不必要的所有信息。

Third, you seem to be of the common but false belief that call stacks are the only system for determining where you are going next, and hence, where you came from.第三,您似乎普遍但错误地认为调用堆栈是确定您下一步要去哪里的唯一系统,因此,您来自哪里。 They are not.他们不是。 As we'll see in the next version of C# and VB, asynchronous control flows utterly divorce "where you came from" from "where you are going next" and do not use call stacks at all.正如我们将在下一版本的 C# 和 VB 中看到的那样,异步控制流完全将“你来自哪里”与“你接下来要去哪里”分开,并且根本不使用调用堆栈。

Perhaps you can tell us why you want this information.也许您可以告诉我们您为什么需要这些信息。 There is probably a better way to do what you want.可能有更好的方法来做你想做的事。

I mean I want to get the references of object in a.do_A() (can be easily attained by this), the reference of object b that called a.do_A(), and the reference of object c that called b.do_B(). I mean I want to get the references of object in a.do_A() (can be easily attained by this), the reference of object b that called a.do_A(), and the reference of object c that called b.do_B( )。

I think this should be possible, because I can get the call hierarchy with call stack, so I'm sure I should be able to get some more information about the objects who called the methods.我认为这应该是可能的,因为我可以通过调用堆栈获得调用层次结构,所以我确信我应该能够获得有关调用方法的对象的更多信息。

In general, what you ask for is not possible in .NET - even in theory.一般来说,你所要求的在 .NET 中是不可能的——即使在理论上也是如此。 Perhaps unintuitively, there's no guarantee that an object is still alive even when an instance-method on that object is in the midst of execution.也许不直观的是,即使 object 上的实例方法正在执行中,也不能保证 object 仍然存在。 Essentially, the CLR is smart enough to recognize when the hidden this reference passed to an instance-method will no longer be dereferenced.本质上,CLR 足够聪明,可以识别何时隐藏的this引用传递给实例方法将不再被取消引用。 The referenced object can then become eligible for collection when this happens (assuming it is not reachable through other roots, of course).发生这种情况时,引用的 object 就可以被收集(当然,假设它不能通过其他根访问)。

As a corollary, it's also perfectly possible for a "calling object" to be dead while the method it has called is still executing.作为推论,“调用对象”也完全有可能在它调用的方法仍在执行死亡。 In your specific example, it's perfectly possible that b and c (really the objects referred to by those variables) don't exist anymore while A.do_A() is executing.在您的具体示例中,在执行A.do_A()bc (实际上是这些变量引用的对象)完全有可能不再存在

What this means of course is that the information you seek may no longer be available in any form in the process, and no "magic" API should be able to reliably produce it.这当然意味着您寻求的信息在此过程中可能不再以任何形式提供,并且没有“魔法” API 应该能够可靠地产生它。

I recommend reading Raymond Chen's article: When does an object become available for garbage collection?我推荐阅读 Raymond Chen 的文章: object 何时可用于垃圾收集? to understand this issue better:为了更好地理解这个问题:

An object can become eligible for collection during execution of a method on that very object.在该 object 上执行方法期间,object 可能有资格被收集。

If you feel this doesn't relate to your question, consider the second-last paragraph in that article:如果您觉得这与您的问题无关,请考虑该文章的倒数第二段:

Another customer asked, "Is there a way to get a reference to the instance being called for each frame in the stack? (Static methods excepted, of course.)" A different customer asked roughly the same question, but in a different context: "I want my method to walk up the stack, and if its caller is OtherClass.Foo, I want to get the this object for OtherClass.Foo so I can query additional properties from it."另一位客户问:“有没有办法获得对堆栈中每个帧调用的实例的引用?(当然,静态方法除外。)”另一位客户提出了大致相同的问题,但在不同的上下文中: “我希望我的方法在堆栈中向上走,如果它的调用者是 OtherClass.Foo,我想为 OtherClass.Foo 获取这个 object,以便我可以从中查询其他属性。” You now know enough to answer these questions yourself.你现在知道的足够多,可以自己回答这些问题。

That is not possible, if A want knowledge of who calls do_A , then do_A must define a parameter object caller and its the caller responsibility to pass the correct object instance to the parameter.这是不可能的,如果A想知道谁调用do_A ,那么do_A必须定义一个参数object caller及其调用者责任将正确的 object 实例传递给参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM