如何在运行时确定方法调用者类型?

时间:2015-06-24 19:54:00

标签: c# .net methods

我想知道方法是否有办法在运行时确定调用它的类型。

[UPD2] 对于这种特殊情况,我只对调用方的类型感兴趣,而不是方法的名称,因此,How can I find the method that called the current method?Retrieving the calling method name from within a method等其他类似问题并不能解决我的问题

为了简单起见,我们假设我有一个名为AnimalContainer的类。 在初始化时,它的构造函数将收到一个允许类型的列表:允许将动物注册到容器的类型。

此类的目标(类似于IoC容器)用作任何希望检索特定动物实例的类型的容器。限制是只有一组任意类型应该能够将动物注册到容器中。然后,如果非允许类型调用该方法,则该方法将返回InvalidOperationException

期望类型或对象参数:

void RegisterAnimal(Type callerType, Animal animal) {...}
// Or
void RegisterAnimal(object invoker, Animal animal) {...}

这些不会起作用,因为调用者不限于指定自己的类型(或实例)。例如:

// Inside class A:
animalContainer.RegisterAnimal(typeof(B), anyAnimal);

[UPD1] 我已经看到很多答案,说这似乎是一个糟糕的方法。如果你这么认为,你会建议另一种方式吗?总的来说,我想要实现的是防御性编码。 按照惯例,我肯定可以拥有允许在该容器中注册动物的类型集。会发生什么,是否有其他开发人员,他们不知道这种情况,尝试在课堂上注册一只动物,并不认为这样做?它将做一些设计并不期待的事情,因此,最有可能最终会引入一些错误。 这只是我能找到的更简单的例子(The AnimalContainer),但它可以扩展到很多情况:

  1. 有一组控制器clases,可以将依赖项注册到IoC容器中。
  2. 使用MessageContainer为不同类型之间的消息注册发布者和下标(解耦事件订阅者应该知道谁正在发布该事件的事实)。然后指定只有一组类型可以发布给定的消息。 例如:任何类都可以侦听NewAnimalArrive消息,但只有一组特定的clases可以触发该事件。

3 个答案:

答案 0 :(得分:1)

好吧,您可以使用反射来访问堆栈跟踪 - 但这很慢,在某些情况下,如果JIT由于内联而跳过了一些堆栈帧,我不会感到惊讶。

一种选择是将方法设为内部方法,并且只包含"允许的方法。同一程序集中的类型。或者将方法设为私有,并且只包含"允许的"类型为外部类型中的嵌套类型。

没有比这更精细的东西 - 如果你需要的不仅仅是"允许的"在程序集中的类型,您应该考虑您的信任模型...您对程序集中最终的其他代码有多少控制权?如果您不信任的其他人可以更改该代码,那么无论如何都会改变游戏,并且他们可以撤消您添加的任何保护。

如果您试图阻止意外做错事,您可以使用Roslyn Code Diagnostic,可能......但从根本上说到目前为止只有这种情况事情可以带你去。

答案 1 :(得分:0)

StackTrace stackTrace = new StackTrace(); Console.WriteLine(stackTrace.GetFrame(1).GetMethod()的名称。);

答案 2 :(得分:0)

这个要求闻起来很糟糕,我怀疑你以不同的方式做事会更好。也就是说,以下代码通常可以获得调用者的类型。我强烈建议不要出于各种原因(包括它缓慢,略有错误这一事实,我是否提到它很慢?

在使用以下代码之前,请考虑一下您的工作。

[MethodImpl(MethodImplOptions.NoInlining)]
private static Type GetCallerType()
  int skipFrames = 2; //Assumes that you are calling this from the method being invoked by the caller. Add stack frames to skip for each method removed, and make sure each one is marked with [MethodImpl(MethodImplOptions.NoInlining)]
  Type declaringType;
  do
  {
    MethodBase method = new StackFrame(skipFrames, false).GetMethod();
    declaringType = method.DeclaringType;
    skipFrames++;
  } while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase));
  return declaringType;
}

代码基于NLog's source code