.net 运行时如何确定方法调用方类型?[duplicate]

qmelpv7a  于 2023-03-20  发布在  .NET
关注(0)|答案(3)|浏览(128)

此问题在此处已有答案

(17个答案)
Retrieving the calling method name from within a method [duplicate](7个答案)
七年前就关门了。
我想知道是否有一种方法可以在运行时确定调用它的类型。
[UPD2]对于这个特定的例子,我只对调用者的Type感兴趣,而不是方法的名称,所以,其他类似的问题,如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]我已经看到很多回答,说这似乎是一个很糟糕的方法。如果你这样认为,你会建议另一种方法吗?一般来说,我试图实现的是防御性编码。我当然可以,按照约定,允许注册容器中的动物的类型集。会发生什么,是任何其他开发人员,谁不知道这个约定,尝试在一个类中注册一个动物不应该这样做吗?它会做一些设计没有预料到的事情,所以,最有可能的结果是引入一些错误。这只是我能找到的最简单的例子(AnimalContainer),但它可以扩展到大量的情况:
1.拥有一组将依赖项注册到IoC容器中的控制器类。
1.拥有一个MessageContainer,为不同类型之间的消息注册发布者和订阅者(分离事件订阅者应该知道谁在发布事件的事实)。然后指定只有一组类型可以发布给定的消息。例如:任何类都可以侦听NewAnimalArrive消息,但只有一组特定的类可以激发该事件。

rqenqsqc

rqenqsqc1#

您可以使用反射来访问堆栈跟踪,但这很慢,而且在某些情况下,如果JIT由于内联而跳过了一些堆栈帧,我也不会感到惊讶。
一种选择是使方法成为内部方法,并且只将“允许的”类型包含在同一程序集中;或者使方法成为私有方法,并且只将“允许的”类型作为嵌套类型包含在外部类型中。
没有比这更细粒度的了--如果您需要程序集中“允许的”类型以外的类型,您应该考虑您的信任模型......您对程序集中的其他代码有多大的控制权?如果您不信任的其他人可以更改该代码,那么游戏就结束了,他们可以撤消您添加的任何保护。
如果你试图防止 * 意外 * 做错事,你可以使用罗斯林代码诊断,潜在的...但基本上只有到目前为止,这种事情可以带你。

jecbmhm3

jecbmhm32#

stackTrace =新的堆栈跟踪();控制台。写入行(堆栈跟踪。获取帧(1)。获取方法()。名称);

oymdgrw7

oymdgrw73#

这个要求听起来很糟糕,我想你最好换种方式。也就是说,下面的代码通常可以让你得到调用者的类型。我强烈建议你不要用它,因为有很多原因(包括它很慢,容易出错,我有没有提到它很慢?)
在使用下面的代码之前,请考虑一下您正在做什么。

[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的源代码

相关问题