如何找到当前函数调用者的对象实例的类型?

not*_*tso 7 .net c# reflection logging

目前我有一个函数CreateLog()用于在构造实例的类之后创建一个带有名称的log4net日志.通常用于:

class MessageReceiver
{
     protected ILog Log = Util.CreateLog();
     ...
}
Run Code Online (Sandbox Code Playgroud)

如果我们删除了大量的错误处理,实现归结为:[编辑:请在本文中进一步阅读更长版本的CreateLog.]

public ILog CreateLog()
{
        System.Diagnostics.StackFrame stackFrame = new System.Diagnostics.StackFrame(1);
        System.Reflection.MethodBase method = stackFrame.GetMethod();
        return CreateLogWithName(method.DeclaringType.FullName);
}
Run Code Online (Sandbox Code Playgroud)

问题是,如果我们将MessageReceiver置于子类中,则日志仍将从MessageReceiver获取其名称,因为这是调用CreateLog的方法(构造函数)的声明类.

class IMReceiver : MessageReceiver
{ ... }

class EmailReceiver : MessageReceiver
{ ... }
Run Code Online (Sandbox Code Playgroud)

这两个类的实例将获得与名称"的messageReceiver"日志,而我想他们是赐名"IMReceiver"和"EmailReceiver".

我知道这很容易通过调用CreateLog时,因为对对象对GetType()方法,我想要做什么创作传递一个参考对象来完成(并完成).

有一些小的理由不喜欢不添加参数,个人感到不安,因为没有找到没有额外参数的解决方案.

是否有人可以告诉我如何实现零参数CreateLog()从子类而不是声明类获取名称?

编辑:

CreateLog函数比上面提到的更多.每个实例有一个日志的原因是能够在日志文件中的不同实例之间有所不同.这由CreateLog/CreateLogWithName对强制执行.

扩展CreateLog()的功能以激发其存在.

public ILog CreateLog()
{
        System.Diagnostics.StackFrame stackFrame = new System.Diagnostics.StackFrame(1);
        System.Reflection.MethodBase method = stackFrame.GetMethod();
        Type type = method.DeclaringType;

        if (method.IsStatic)
        {
            return CreateLogWithName(type.FullName);
        }
        else
        {
            return CreateLogWithName(type.FullName + "-" + GetAndInstanceCountFor(type));
        }
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢编写ILog Log = Util.CreateLog(); 而不是每当我写一个新类时,从其他文件中复制一些长的神秘线.我知道,在Util.CreateLog使用的反射不能保证工作,虽然 - 是System.Reflection.MethodBase.GetCurrentMethod()保证工作?

Ori*_*rds 1

有谁可以向我展示如何实现零参数 CreateLog() ,该函数从子类而不是声明类获取名称?

我认为您无法通过查看堆栈框架来做到这一点。

当你的类是 时IMReceiver,对方法的调用CreateLog是在MessageReceiver类中。堆栈帧必须告诉您该方法是从哪里调用的,否则它就没有任何用处,所以它总是会说MessageReceiver

如果您CreateLog在您的类和其他类中显式调用IMReceiver,那么它会起作用,因为堆栈帧显示在派生类中调用的方法(因为它实际上是)。

这是我能想到的最好的办法:

class BaseClass{
  public Log log = Utils.CreateLog();
}
class DerivedClass : BaseClass {
  public DerivedClass() {
    log = Utils.CreateLog();
  }
}
Run Code Online (Sandbox Code Playgroud)

如果我们跟踪日志的创建,我们会得到:

new BaseClass();
# Log created for BaseClass

new DerivedClass();
# Log created for BaseClass
# Log created for DerivedClass
Run Code Online (Sandbox Code Playgroud)

第二个“为派生类创建的日志”会覆盖实例变量,因此您的代码将正常运行,您只需创建一个立即被丢弃的 BaseClass 日志。这对我来说似乎很糟糕,我只是在构造函数中指定类型参数或使用泛型。

恕我直言,指定类型比在堆栈帧中四处查看要干净得多

如果您无需查看堆栈框架即可获得它,那么您的选择范围就会大大扩展