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

class MessageReceiver
{
     protected ILog Log = Util.CreateLog();
     ...
}

如果我们消除大量错误处理,则实现可归结为:
[编辑:请在这篇文章中进一步阅读CreateLog的更长版本。]
public ILog CreateLog()
{
        System.Diagnostics.StackFrame stackFrame = new System.Diagnostics.StackFrame(1);
        System.Reflection.MethodBase method = stackFrame.GetMethod();
        return CreateLogWithName(method.DeclaringType.FullName);
}

问题是,如果我们将MessageReceiver继承到子类中,则日志仍将取自MessageReceiver的名称,因为这是调用CreateLog的方法(构造函数)的声明类。
class IMReceiver : MessageReceiver
{ ... }

class EmailReceiver : MessageReceiver
{ ... }

这两个类的实例都将获得名称为“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));
        }
}

我也更喜欢写ILog Log = Util.CreateLog();而不是每当我编写一个新类时都从另一个文件中复制一些冗长的行。我知道虽然不能保证在Util.CreateLog中使用的反射正常工作-是否可以保证System.Reflection.MethodBase.GetCurrentMethod()有效?

最佳答案



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

当您的类是IMReceiver时,对CreateLog方法的调用在MessageReceiver类中。堆栈框架必须告诉您从何处调用该方法,否则将无济于事,因此总是会说MessageReceiver
如果您在CreateLog和其他类中显式调用了IMReceiver,则它可以正常工作,因为堆栈框架显示了派生类中正在调用的方法(因为实际上是这样)。

这是我能想到的最好的事情:

class BaseClass{
  public Log log = Utils.CreateLog();
}
class DerivedClass : BaseClass {
  public DerivedClass() {
    log = Utils.CreateLog();
  }
}

如果我们跟踪日志的创建,则会得到以下信息:
new BaseClass();
# Log created for BaseClass

new DerivedClass();
# Log created for BaseClass
# Log created for DerivedClass

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

恕我直言,指定该类型比在堆栈框架中四处浏览都更干净

如果您不用看堆栈框架就能得到它,那么您的选择就可以大大扩展

关于c# - 如何找到当前函数的调用者的对象实例的类型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/338740/

10-14 17:17