Lets say I have 3 classes:
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() ?
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.
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 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. 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. Essentially, the CLR is smart enough to recognize when the hidden this
reference passed to an instance-method will no longer be dereferenced. The referenced object can then become eligible for collection when this happens (assuming it is not reachable through other roots, of course).
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.
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.
I recommend reading Raymond Chen's article: When does an object become available for garbage collection? to understand this issue better:
An object can become eligible for collection during execution of a method on that very 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." 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.
精彩评论