Обновлено: Предупреждение. Теперь я понимаю, что следующий метод обычно считается плохой идеей, потому что он создает скрытые зависимости, чтобы выглядеть аккуратно.
Недавно я обнаружил, что вы можете использовать StackTrace для вывода информации о вызывающем методе.
Это позволяет вам создать, казалось бы, «крутой» API, посредством которого вы просто вызываете метод, не беспокоясь о передаче ему каких-либо явных параметров, и метод определяет, что делать, на основе StackTrace.
Это плохо, и если да, то почему?
Пример:
public class Cache {
public Object CheckCache()
{
Object valueToReturn = null;
string key = GenerateCacheKeyFromMethodPrototype(new StackTrace().GetFrame(1).GetMethod()); //frame 1 contains caller
if (key is in cache) valueToReturn = itemFromCache;
return valueToReturn;
}
}
public class Foo {
private static Cache cache = new Cache();
public Blah MethodFoo(param1, param2...)
{
Blah valueToReturn = cache.CheckCache(); //seems cool!
if (valueToReturn == null)
{
valueToReturn = result of some calculation;
//populate cache
}
return valueToReturn;
}
}
Я уверен, что в приведенном выше псевдокоде есть ошибки, но вы меня поняли.
Обновлено: спасибо за все ответы.





Есть две причины, по которым этого не делать:
Если вы хотите сделать это, вам лучше использовать инструмент, поддерживающий аспектно-ориентированное программирование, например динамический прокси Castle.
спасибо за ответ - пожалуйста, не могли бы вы подробнее объяснить, почему это хрупкое?
Что происходит при удалении вызывающего метода? В вашем примере это не так важно, но в других, более реальных случаях это может иметь значение. Кроме того, что происходит, когда есть перегруженные методы? Будет ли эта техника проверки стека, чтобы решить, что делать, по-прежнему правильно?
Другая проблема заключается в том, что компилятор может «встроить» ваш метод в процесс оптимизации, например
void MethodA() {
MethodB();
}
void MethodB() {
foo();
}
становится:
void MethodA() {
foo();
}
Это, очевидно, проблема, потому что непосредственно вызывающий foo не является MethodB, а является MethodA. Однако есть атрибут, который вы можете поместить в свой метод, чтобы предотвратить его встраивание:
[MethodImpl( ... NoInline )]
(Не могу вспомнить точный параметр)
-Oisin
[MethodImpl (MethodImplOptions.NoInlining)] - это параметр. Хотя, как говорили другие, это должен быть последний вариант. Я нашел только половину правильного использования для этого за столько лет программирования.
Это плохо, потому что я не могу знать, что делает функция, когда я ее вызываю. Я не могу протестировать функцию, потому что мой тест вызовет ее из другой функции, что может вызвать другое поведение.
И это плохо, потому что теперь есть «невидимый» контракт, которому я должен подчиняться при вызове функции. Я не только должен убедиться, что переданы правильные параметры, я также должен убедиться, что текущая функция имеет правильное имя. Что, если бы я заключил вызов функции в анонимную лямбда-функцию? Внезапно я изменил поведение программы, и нет догадался об этом заранее, так что теперь я могу потратить следующий день на отладку, почему программа внезапно и волшебным образом сломалась.
Что происходит с перегруженными функциями? Вы их различаете? Функции с одинаковым именем, но в разных классах? Функции со «особыми» именами, такие как конструктор, финализатор, операторы или лямбды?
А как насчет того, чтобы функции были встроены компилятором?
Мне это совсем не кажется крутым. Зачем вам включать все возможные способы получения требуемого состояния в самом методе? Это похоже на антишаблон для внедрения зависимостей. Не ходи туда.
хорошо, спасибо за ваш ответ. Теперь я вижу, что такой подход влечет за собой целый ряд проблем.
У меня был аналогичный вопрос, так как я хотел выполнить код, условно основанный на вызывающем методе: stackoverflow.com/questions/213192/…. Компромиссы того не стоили, ИМО