Получить иерархию вызовов объектов - PullRequest
2 голосов
/ 05 июля 2011

Допустим, у меня есть 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();
    }
}

А потом я звоню:

C c;
c.do_C();

Как я могу получить иерархию вызовов объекта из do_A () А?

Я имею в виду, я хочу получить ссылки на объект в a.do_A () (может быть легко достигнуто с помощью this), ссылка на объект b который вызвал a.do_A () , и ссылку на объект c , который вызвал b.do_B () .

Я думаю, что это возможно, потому что я могу получить иерархию вызовов с помощью стека вызовов, поэтому я уверен, что смогу получить больше информации об объектах, которые вызвали методы.

Ответы [ 3 ]

12 голосов
/ 05 июля 2011

Прежде всего, то, что вы описываете, является плохой практикой программирования.Поведение метода должно зависеть от аргумента , а не от того, кто его вызвал .Метод должен быть надежным, чтобы вы знали, что вы получаете одно и то же поведение независимо от того, кто его вызвал.

Во-вторых, вы, похоже, придерживаетесь общего, но ложного убеждения, что стек вызовов - это реальная вещь, которая сообщает вам, откуда поступил звонок .Это совсем не цель стека вызовов, хотя для сценариев отладки это, безусловно, полезно.Цель стека вызовов - сообщить вам , куда вы идете дальше , а не , откуда вы пришли .Так вот, обычно это тот случай, когда вы идете дальше, также откуда вы пришли.Тот факт, что вы часто можете определить, откуда вы пришли, основываясь на знании того, куда вы идете дальше, часто полезен, но вы не можете полагаться на него.Разрешено, чтобы в стеке вызовов содержалось только информации, достаточной для определения того, куда вы собираетесь двигаться дальше;он может отбрасывать каждый бит информации, необязательный для определения того, куда вы идете дальше.

В-третьих, вы, похоже, придерживаетесь общего, но ложного убеждения, что стеки вызовов являются единственной системой для определения того, куда вы идете дальше.и, следовательно, откуда вы пришли.Они не.Как мы увидим в следующей версии C # и VB, асинхронное управление полностью разводится «откуда вы пришли», «откуда вы идете дальше» и вообще не использует стеки вызовов.

Возможно, вы можете сказать нам , почему вам нужна эта информация.Вероятно, есть лучший способ сделать то, что вы хотите.

4 голосов
/ 05 июля 2011

Я имею в виду, я хочу получить рекомендации объект в a.do_A () (может быть легко достигнуто этим), ссылка объект b, который вызвал a.do_A (), и ссылка на объект с, который называется b.do_B ().

Я думаю, это должно быть возможно, потому что я могу получить иерархию вызовов со стеком вызовов, так что я уверен, что я должен быть в состоянии получить больше информации об объектах, которые называют методы.

В общем, то, что вы просите, невозможно в .NET - даже теоретически. Возможно, неинтуитивно, нет никакой гарантии, что объект все еще жив, даже когда метод экземпляра для этого объекта находится в середине выполнения. По сути, CLR достаточно умен, чтобы распознавать, когда скрытая ссылка this, переданная методу экземпляра, больше не будет разыменовываться. При этом объект, на который ссылаются, может стать пригодным для сбора, когда это происходит (конечно, при условии, что он не доступен через другие корни).

Как следствие, вполне возможно, что "вызывающий объект" будет мертв , в то время как вызываемый им метод все еще выполняется. В вашем конкретном примере вполне возможно, что b и c (на самом деле объекты, на которые ссылаются эти переменные) больше не существуют , пока A.do_A() выполняется.

Это, конечно, означает, что запрашиваемая вами информация может больше не быть доступной в какой-либо форме в процессе, и никакой "магический" API не сможет ее надежно создать.

Я рекомендую прочитать статью Рэймонда Чена: Когда объект станет доступен для сборки мусора? , чтобы лучше понять эту проблему:

Объект может получить право на сбор во время выполнения метод на этом самом объекте.

Если вы считаете, что это не относится к вашему вопросу, рассмотрите второй-последний абзац в этой статье:

Другой клиент спросил: «Есть ли способ получить ссылку на экземпляр вызывается для каждого кадра в стек? (Статические методы исключены, из конечно.) "Другой клиент спросил примерно такой же вопрос, но в другой контекст: «Я хочу, чтобы мой метод идти вверх по стеку, и если его вызывающий абонент - OtherClass.Foo, я хочу получить этот объект для OtherClass.Foo так что я могу запросить дополнительные свойства от этого. "Теперь вы знаете достаточно, чтобы Ответь на эти вопросы сам.

1 голос
/ 05 июля 2011

Это невозможно, если A хочет знать, кто вызывает do_A, тогда do_A должен определить параметр object caller и обязанность вызывающего абонента передать правильный экземпляр объекта параметру.

...