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.
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.
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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With