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

发布于 2024-09-01 17:23:00 字数 854 浏览 4 评论 0原文

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

往日情怀 2024-09-08 17:23:00

这正是 AOP(面向方面​​编程)的任务。看看 PostSharp,它是一个 .NET AOP 框架,它可以让你准确地做你想做的事情想。

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

编辑:看来PostSharp现在是一个商业产品。如果您正在寻找开源(免费)解决方案,我建议 LinFu AOP< /a>.

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.

So尛奶瓶 2024-09-08 17:23:00

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

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 获取调用类型的费用相比,这不算什么(取决于所使用的记录器)。

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

找个人就嫁了吧 2024-09-08 17:23:00

.NET 中的属性不是影响类的装饰器/活动组件/他们所依附的成员。 属性是可以通过反射检索的元数据。尽管有 AOP 解决方案可以根据您的需要扩展 .NET,但 C# 中没有类似装饰器的工具。最简单的解决方案可能是将这一行复制到每个类中。

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.

忆伤 2024-09-08 17:23:00

我们封装了 log4net,这样我们就可以轻松地将其切换出来。我们将来很可能会改变主意。

虽然我们没有这样做,但这样做可能会影响性能......而且我真的很犹豫是否建议这样做,因为我不确定这是一个好主意......你可以...如果你觉得足够邪恶......包装 log4net 并在你的包装器中执行类似的操作。

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

如果您对日志记录方式很了解,则只有在需要日志消息时才会产生该成本。

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.

旧伤还要旧人安 2024-09-08 17:23:00

伙计,这在Python中是轻而易举的事情。我会研究 C# 属性。

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

予囚 2024-09-08 17:23:00

如果这是 ASP.NET 或 Windows 窗体,您只需创建所有窗体/页面派生自的基本页面或基本窗体。您可以将该成员声明为该级别,并可能实现您想要的目标。

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.

鱼忆七猫命九 2024-09-08 17:23:00

您可以借助 PostSharp 或其他面向方面的编程工具来实现此解决方案。

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

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.

も让我眼熟你 2024-09-08 17:23:00

也许一个简单的方法是在接口上编写扩展方法,然后你的类只需要“实现”(但不是真的,因为扩展执行了 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));
    }
  }

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));
    }
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文