简体   繁体   English

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

[英]Class decorator to declare static member (e.g., for log4net)?

I'm using log4net, and we have a lot of this in our code: 我正在使用log4net,我们的代码中有很多这样的东西:

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

One downside is that it means we're pasting this 10-word section all over, and every now and then somebody forgets to change the class name. 一个缺点是,这意味着我们将这个10字的部分粘贴在一起,并且偶尔会有人忘记更改类名。 The log4net FAQ also mentions this alternative possibility, which is even more verbose: log4net常见问题解答还提到了这种替代可能性,这种可能性更加冗长:

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

Is it possible to write a decorator to define this? 是否可以编写装饰器来定义它? I'd really like to say simply: 我真的想简单地说:

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

I've done similar things in other languages, but never a statically-compiled language like C#. 我在其他语言中做过类似的事情,但从来没有像C#这样的静态编译语言。 Can I define class members from a decorator? 我可以从装饰器定义类成员吗?

Edit : Heh. 编辑 :嘿。 I'm a Lisp programmer. 我是Lisp程序员。 I appreciate the suggestions to switch languages, but really, if I was going to switch languages for better metaprogramming capabilities, I'd go all the way to Lisp instead of being half-assed about it. 我很欣赏切换语言的建议,但实际上,如果我要切换语言以获得更好的元编程功能,我会一直到Lisp,而不是半途而废。 Unfortunately using a different language isn't an option on this project. 不幸的是,使用不同的语言不是这个项目的选择。

This is exactly a task for AOP - Aspect Oriented Programming. 这正是AOP的一项任务 - 面向方面编程。 Have a look at PostSharp , it's a .NET AOP framework, it will allow you to do exactly what you want. 看看PostSharp ,它是一个.NET AOP框架,它可以让你完全按照自己的意愿行事

This works by modifying (or weaving) IL code in post-compilation, and adding the logging aspect to the decorated method. 这通过在编译后修改(或编织)IL代码并将日志记录方面添加到修饰方法来实现。

EDIT: It appears that PostSharp now is a commercial product. 编辑: PostSharp现在似乎是一个商业产品。 If you're looking for an open-source (free) solution, I suggest LinFu AOP . 如果您正在寻找开源(免费)解决方案,我建议使用LinFu AOP

We use something almost identical: 我们使用几乎相同的东西:

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

This method is implemented as follows: 该方法实现如下:

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

It still proves to be more of a pain that I'm willing to go through. 它仍然被证明是一种我愿意经历的痛苦。 I much prefer a static object with static methods for logging. 我更喜欢使用静态方法进行日志记录的静态对象。 Obtaining the calling method is not that expensive provided your not getting file info. 如果您没有获取文件信息,获取调用方法并不昂贵。 Compared to the expense of just calling Log4Net obtaining the calling type is nothing (depending some on the loggers used). 与仅调用Log4Net的费用相比,获取调用类型是没有的(取决于使用的记录器的一些)。

Attributes in .NET are not decorators / active components that influence the class/member they're attached to. .NET中的属性不是影响它们所附加的类/成员的装饰器/活动组件。 Attributes are meta-data that can be retrived with reflection. 属性是可以使用反射重新获取的元数据 There is no decorator-like facility in C#, although there are AOP solutions that extend .NET with what you want. C#中没有类似装饰器的工具,尽管有一些AOP解决方案可以根据您的需要扩展.NET。 The simplest solution is probably to just copy that line to each class though. 最简单的解决方案可能只是将该行复制到每个类。

We wrapped log4net so we could switch it out with ease. 我们包装了log4net,因此我们可以轻松地将其切换出来。 It is something that we could very possibly change our mind on in the future. 这是我们未来可能会改变主意的事情。

While we are not doing this, and you will probably take a performance hit to do so....and I'm really hesitant to even suggest it because I'm not sure it is a good idea.....you could...if you felt devilish enough....wrap log4net and do something like this in your wrapper. 虽然我们没有这样做,但你可能会受到性能影响......我甚至不愿建议它,因为我不确定这是一个好主意.....你可以...如果你觉得很恶心......包装log4net并在你的包装器里做这样的事情。

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

If you're smart about how you're logging you could only incur that cost when you need the log message. 如果您对自己的日志记录非常了解,那么在需要日志消息时只能产生这笔费用。

Man this would be a breeze in python. 在蟒蛇中,这将是一件轻而易举的事。 I would look into C# Attributes. 我会研究C#Attributes。

If this is ASP.NET or Windows Forms, you can just create a base Page or base Form that all your Forms/Pages derive from. 如果这是ASP.NET或Windows窗体,您只需创建所有窗体/页面派生自的基页或基本窗体。 You can declare this member at that level and probably achieve what you desire. 您可以在该级别声明此成员,并可能达到您的期望。

You could probably implement a solution for this with the help of PostSharp , or another Aspect Oriented Programming tool. 您可以在PostSharp或其他面向方面编程工具的帮助下为此实现解决方案。

It would be pretty trivial using a macro in Boo, but that wouldn't help your situation much. 使用Boo中的宏会非常简单,但这对你的情况没有多大帮助。

Perhaps an easy way would be to write an extension method on an Interface, then your class just need to "implement" (but not really because the extension does the impl) the interface 也许一种简单的方法是在接口上编写扩展方法,然后你的类只需要“实现”(但不是因为扩展实际上是impl)接口

public class Foo : IGetLog<Foo>
{

}

The extension something like.... 扩展类似....

  public interface IGetLog<T> { }

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM