使用StackTrace来推断方法的调用者

时间:2008-11-25 18:13:06

标签: c# stack-trace

编辑:警告 - 我现在意识到以下技术通常被认为是一个坏主意,因为它为了看起来整洁而创建隐藏的依赖。


我最近发现您可以使用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;
  }
}

我确定上面的伪代码存在错误,但你得到了我的漂移。


编辑:感谢大家的回复。

4 个答案:

答案 0 :(得分:5)

为什么不这样做有两个原因:

  • 这很慢
  • 它创造了一个脆弱的解决方案。

如果您想这样做,最好使用支持面向方面编程的工具,例如Castle的动态代理。

答案 1 :(得分:4)

另一个问题是编译器可能会在优化过程中“内联”您的方法,例如

void MethodA() {
    MethodB();
}

void MethodB() {
   foo();
}

变为:

void MethodA() {
   foo();
}

这显然是一个问题,因为foo的直接调用者不再是MethodB,而是MethodA。您可以在方法上放置一个属性,以防止它被内联:

[MethodImpl( ... NoInline )]

(我记不起确切的参数)

-Oisin

答案 2 :(得分:3)

这很糟糕,因为当我调用它时,我无法知道函数的作用。我无法测试该函数,因为我的测试将从不同的函数调用它,这可能会调用不同的行为。

这很糟糕,因为在调用函数时我必须遵守“隐形”合约。我不仅要确保传递正确的参数,还必须确保当前函数具有正确的名称。如果我在匿名lambda函数中包装函数调用怎么办?突然之间我改变了程序的行为,而且没有提前猜到了,所以现在我可以在第二天调试为什么程序突然而且神奇地破坏了。

重载函数会发生什么?你区分它们吗?具有相同名称但在不同类中的函数?具有“特殊”名称的函数,如构造函数,终结函数,运算符或lambdas?

当编译器内联函数时呢?

答案 3 :(得分:1)

这对我来说似乎并不酷。为什么要在方法本身中采用一切可能的方式来获得所需的状态?这就像依赖注入的反模式。不要去那里。