类装饰器声明静态成员(例如,用于log4net)?

时间:2010-05-17 21:24:07

标签: c# decorator static-members

我正在使用log4net,我们的代码中有很多这样的内容:

public class Foo {
    private static readonly ILog log = LogManager.GetLogger(typeof(Foo));
    ....
}

一个缺点是,这意味着我们正在粘贴这个10字的部分,偶尔会有人忘记改变课程名称。 log4net FAQ也提到了这种替代可能性,这种可能性更加冗长:

public class Foo {
    private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    ...
}

是否可以编写装饰器来定义它?我真的很想简单地说:

[LogMe]  // or perhaps: [LogMe("log")]
public class Foo {
    ...
}

我在其他语言中做过类似的事情,但从来没有像C#这样的静态编译语言。我可以从装饰器定义类成员吗?

修改:嘿。我是Lisp程序员。我很欣赏切换语言的建议,但实际上,如果我要切换语言以获得更好的元编程功能,我会一直到Lisp,而不是半途而废。不幸的是,使用不同的语言不是这个项目的选择。

8 个答案:

答案 0 :(得分:5)

这正是AOP的一项任务 - 面向方面编程。看看PostSharp,这是一个.NET AOP框架,它可以让你完全按照自己的意愿行事。

这可以通过在编译后修改(或编织)IL代码,并将日志记录方面添加到装饰方法来实现。

编辑: PostSharp现在看来是商业产品。如果您正在寻找开源(免费)解决方案,我建议LinFu AOP

答案 1 :(得分:3)

我们使用几乎相同的东西:

private static readonly ILog Logger = LogManager.GetLogger();

此方法实现如下:

[MethodImpl(MethodImplOptions.NoInlining)]
public static ILog GetLogger()
{
    Type t;
    try { t = new StackFrame(1, false).GetMethod().DeclaringType; }
    catch { t = typeof(UnknownObject); }
    return GetLogger(t);
}
private static class UnknownObject { }

它仍然证明是我愿意经历的更多痛苦。我更喜欢使用静态方法进行日志记录的静态对象。如果您没有获取文件信息,获取调用方法并不昂贵。与仅调用Log4Net的费用相比,获取调用类型是没有的(取决于所使用的记录器的一些)。

答案 2 :(得分:1)

.NET中的

Attributes不是影响它们所附加的类/成员的装饰器/活动组件。 属性是元数据,可以通过反射进行重新审核。 C#中没有类似装饰器的工具,尽管有一些AOP解决方案可以根据您的需要扩展.NET。最简单的解决方案可能就是将该行复制到每个类中。

答案 3 :(得分:1)

我们包装了log4net,因此我们可以轻松地将其切换出来。这是我们未来可能会改变主意的事情。

虽然我们没有这样做,但你可能会受到性能影响......而且我甚至犹豫不决,因为我不确定它是个好主意....你可以......如果你觉得很恶心......包装log4net并在你的包装器里做这样的事情。

var callingType = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType

如果您对自己的日志记录非常了解,那么在您需要日志消息时只会产生这笔费用。

答案 4 :(得分:0)

在Python中,这将是一件轻而易举的事。我会调查C# Attributes.

答案 5 :(得分:0)

如果这是ASP.NET或Windows窗体,您只需创建所有表单/页面派生自的基本页面或基本表单。您可以在该级别声明此成员,并可能实现您的目标。

答案 6 :(得分:0)

您可以在PostSharp或其他面向方面编程工具的帮助下为此实现解决方案。

使用Boo中的宏会非常简单,但这对你的情况没有多大帮助。

答案 7 :(得分:0)

也许一种简单的方法是在接口上编写扩展方法,然后你的类只需要“实现”(但不是因为扩展实际上是impl)接口

public class Foo : IGetLog<Foo>
{

}

扩展类似....

  public interface IGetLog<T> { }

  public static class IGetLogExtension
  {
    public static ILog GetLogger<T>(this IGetLog<T> getLog)
    {
      return LogManager.GetLogger(typeof(T));
    }
  }