【问题标题】:Inserting code into C# methods right before compilation在编译之前将代码插入 C# 方法
【发布时间】:2016-06-10 07:46:54
【问题描述】:

我有几个从 WinForms 应用程序的入口点调用的方法。这些方法依次调用其他方法,有时还相互调用。

在每个方法的入口处,我都插入了如下代码:

public static bool IsDebug
{
    #if (DEBUG)
        return (true);
    #else
        return (false);
    #endif
}

public void SomeMethod ()
{
    if (IsDebug) { Logger.WriteMethodTrace(MethodBase.GetCurrentMethod().Name); }
}

这种方法有两个问题:

  • 每种方法都是手写的。
  • 它使用反射,对于经常调用的方法来说太慢了。

.
REFLECTION:新的 C# nameof(parameter) 关键字可以很好地用于参数名称,但我还没有找到类似的方法名称构造。我考虑过创建某种静态字典来保存 TypeMethodInfo 详细信息,但似乎没有办法在运行时提取方法名称而不进行反射以用作字典中的键。

手工编写:即使有避免反射的解决方案,每种方法都需要手动更改,这既繁琐又容易出错。我想知道是否有办法在编译之前及时插入一行代码。不确定 VS 扩展或 Roslyn 是否会有所帮助。理想情况下,如果可以进行自动插入,则插入应该在不实际修改源代码的情况下进行。

请注意,分析堆栈跟踪不是一种选择。我一直在走这条路,而且很慢而且很不愉快。

任何指针/建议将不胜感激。

【问题讨论】:

  • 可以使用AOP(面向切面编程)范式。 C# 世界中最著名的代表是 PostSharp。它的免费版本可以做你想做的事。
  • 为什么不简单地使用 TraceListener 并在 app.config 中根据需要打开或关闭它?
  • @Evk:尽管问题已经得到解答,但 PostSharp 似乎是一个值得探索的好建议。谢谢!
  • @RaheelKhan 考虑到使用当前方法,您无法在运行时切换日志记录级别(实际上您甚至无法通过配置进行切换) - 您必须重新编译代码才能做到这一点。大多数情况下,您希望在已运行的应用程序上启用调试级日志记录。
  • @Evk:你是对的。但是,当在 SO 上发布问题时,我倾向于缩小上下文和代码范围以提出一个简洁的问题。这里的上下文不是关于如何使用最佳实践进行记录。接受的答案对于我的目的来说足够灵活(不包括自动化)。

标签: c# .net reflection compilation roslyn


【解决方案1】:

C# 5.0 为您提供了一个不错的功能。我想你试试这个会很有用:

[Conditional("DEBUG")]
public void LogMethodNameInDebug(
    [CallerMemberName] string memberName = "",
    [CallerFilePath] string sourceFilePath = "", 
    [CallerLineNumber] int sourceLineNumber = 0)
{
    Logger.WriteMethodTrace(memberName);
)


public void SomeMethod()
{
    LogMethodNameInDebug(); // don't fillin the methodnames yourself, the compiler will do.
}

[Conditional("DEBUG")] 将在将其编译为 Release 版本时排除该方法。查找更多信息:MSDN - ConditionalAttribute

[CallerMemberName]会在编译时填充(它会填充调用者的参数,所以不使用反射或堆栈分析)。更多关于[CallerMemberName]的信息在这里:MSDN - CallerMemberNameAttribute

【讨论】:

  • Nitpick:这是 C# 5.0 的一个特性,而不是 .Net 4.5。
  • @Jeroen,谢谢!太棒了。最重要的是,我可以使用基于 Roslyn 的扩展来确保在每个函数的开头调用此方法。
  • @JeroenvanLangen 是的,该属性来自 .Net 4.5,但这不是重要的部分,它是 caller information support in the compiler。您可以使用提供属性的a library 将调用者信息与 C# 5.0 和 .Net 4.0 一起使用。相反,调用者信息不适用于 C# 4.0 和 .Net 4.5,即使属性可用。
  • @svick A, *light bulb* 你是对的。 C# 5.0 负责填写参数。我会纠正它。感谢您的批判性阅读。
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多