我正在使用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,而不是半途而废。不幸的是,使用不同的语言不是这个项目的选择。
答案 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)
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));
}
}