我可以通过函数传递参数属性吗?

时间:2018-07-31 19:28:50

标签: c# logging

奇怪而又非常具体的问题。现在,我们有一个使用CallerMemberNameAttribute的日志记录界面,如下所示:

interface ILogger
{
    void Info(string message, [CallerMemberName] string memberName = "");
}

这都是伟大而完美的,并且在我们的实施中效果很好。但是,提出了一个要求,我们需要编写一些可以在我们的流程以及其他地方调用的函数,并且这些函数需要使用一个定义为ITracer的类,如下所示:

interface ITracer
{
    void TraceInformation(string message);
}

因此,当在我们的环境中运行时,这些功能应记录到当前的日志记录基础结构中,但是在其他环境中运行时,它具有自己的ITracer集,可以完成自己的工作。因此,我编写了一个垫片,该垫片在环境中被调用时只会传递消息:

class Logger : ILogger
{
    public void Info(string message, [CallerMemberName] string memberName = "") => // log some stuff

    public ITracer GetTraceWriter() => return new TraceWriter(this);
}

class TraceWriter : ITracer
{
    public TraceWriter(ILogger logger) => this.logger = logger;

    public void TraceInformation(string message) => this.logger.Info($"{message}");
}

这可以正常工作,但是memberName是输出的日志消息的一部分,在此实现中,当TraceWriter开始记录日志时,它始终具有等于{{1}的memberName }。有什么方法可以通过函数调用将此参数属性传递给吗?这里的主要问题是我无法更改TraceInformation界面。

想到但无法解决的解决方案:

  • 更改ITracer中的TraceInformation调用以返回对ITracer的函数调用,该函数调用可以直接从方法中调用(无法执行此操作,因为我无法更改ITracer接口)

1 个答案:

答案 0 :(得分:0)

您可能会做的,也许是不理想的事情,是使用StackFrame类在调用函数中查找堆栈。

您可以使用它来遍历堆栈,以查找(或排除)特定类型,或者实现特定接口的类型-或更简单地只是“向上”堆栈特定数量的帧。

如果将此内容包含在void Info(..)的实现中,则可以按以下方式访问方法名称

# get the name of the current method (i.e. Info)
new StackFrame(0, false).GetMethod().Name

# get the name of the calling method (i.e. TraceInformation)
new StackFrame(1, false).GetMethod().Name

# get the name of the parent calling method - what you are looking for 
new StackFrame(2, false).GetMethod().Name

当然,您需要从ITracer对象调用该方法时以及直接调用该方法时进行协调。您还可以获取调用对象,检查它们实现了哪些接口,并记录适当的方法名称。

这全部使用反射,因此您需要考虑性能影响,但是我希望CallerMemberName也使用反射/可能会产生类似的影响。