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

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

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

一个缺点是,这意味着我们将这个10字的部分粘贴在一起,并且偶尔会有人忘记更改类名。 log4net常见问题解答还提到了这种替代可能性,这种可能性更加冗长:

 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程序员。 我很欣赏切换语言的建议,但实际上,如果我要切换语言以获得更好的元编程function,我会一直到Lisp而不是半途而废。 不幸的是,使用不同的语言不是这个项目的选择。

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

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

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

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

 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 { } 

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

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

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

虽然我们没有这样做,但你可能会受到性能打击….我甚至不愿建议它,因为我不确定这是一个好主意…..你可以…如果你觉得很恶心……包装log4net并在你的包装器里做这样的事情。

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

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

在python中,这将是一件轻而易举的事。 我会研究C#Attributes。

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

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

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

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

 public class Foo : IGetLog { } 

扩展类似….

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