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

二次信任 提交于 2019-12-23 09:55:17

问题


I'm using log4net, and we have a lot of this in our code:

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. The log4net FAQ also mentions this alternative possibility, which is even more verbose:

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#. Can I define class members from a decorator?

Edit: Heh. I'm a Lisp programmer. 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. Unfortunately using a different language isn't an option on this project.


回答1:


This is exactly a task for AOP - Aspect Oriented Programming. Have a look at PostSharp, it's a .NET AOP framework, it will allow you to do exactly what you want.

This works by modifying (or weaving) IL code in post-compilation, and adding the logging aspect to the decorated method.

EDIT: It appears that PostSharp now is a commercial product. If you're looking for an open-source (free) solution, I suggest LinFu AOP.




回答2:


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).




回答3:


Attributes in .NET are not decorators / active components that influence the class/member they're attached to. 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. The simplest solution is probably to just copy that line to each class though.




回答4:


We wrapped log4net so we could switch it out with ease. 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.

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.




回答5:


Man this would be a breeze in python. I would look into C# Attributes.




回答6:


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. You can declare this member at that level and probably achieve what you desire.




回答7:


You could probably implement a solution for this with the help of PostSharp, or another Aspect Oriented Programming tool.

It would be pretty trivial using a macro in Boo, but that wouldn't help your situation much.




回答8:


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

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));
    }
  }


来源:https://stackoverflow.com/questions/2852923/class-decorator-to-declare-static-member-e-g-for-log4net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!