Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中是否有对行号的编译时访问?_C# - Fatal编程技术网

在C#中是否有对行号的编译时访问?

在C#中是否有对行号的编译时访问?,c#,C#,我正在使用VisualStudio2010编写一个C#程序,其中我想将某些事件写入日志文件,并包括发生事件时代码所在的行号 我只找到了两种获取行号的方法——CallerLineNumber,它需要.Net 4.5/C#5(我的目标是.Net 4)和StackFrame.GetFileLineNumber,它显然需要调试版本和pdb文件才能正常工作,而我生成的是发布版本而不是pdb文件 但是这里我没有得到什么-上面两个都是运行时解决方案,但是行号是编译时实体。为什么需要运行时解决方案 我可以输入正

我正在使用VisualStudio2010编写一个C#程序,其中我想将某些事件写入日志文件,并包括发生事件时代码所在的行号

我只找到了两种获取行号的方法——CallerLineNumber,它需要.Net 4.5/C#5(我的目标是.Net 4)和StackFrame.GetFileLineNumber,它显然需要调试版本和pdb文件才能正常工作,而我生成的是发布版本而不是pdb文件

但是这里我没有得到什么-上面两个都是运行时解决方案,但是行号是编译时实体。为什么需要运行时解决方案

我可以输入正确的行号作为文字常量,只需查看屏幕底部的“ln 175”之类的内容

但问题是,如果我在第175行之前编辑任何代码,我的文字可能不再正确。但是编译器知道正确的行号,我过去使用过编程语言,它可以将正确的行号作为编译时常量。(例如,ANSI C和微软C++支持一个预定义宏
有没有办法让C来做这件事?如果没有,我的问题有什么解决办法吗?

一个选择是使用


在我看来,行号是错误的方法。让我解释一下:

175号线有多独特?即使找到了解决方案,下一个问题是:它是哪个文件?它会重复:如果你知道这个文件,你会问自己:它是哪个版本的文件?您将集成源代码管理系统的修订号。一旦你这么做了,问题就会出现:谁在调用那个代码

如果您正在调试异常,请使用调试器并在第一次出现异常时中断

如果您在分析性能问题,行号无关紧要,任何独特的都可以。试试内存分析器

如果您的方法太长,无法识别问题,请重构代码并缩短方法。通过简短的方法,您可以使用像PostSharp这样的AOP框架及其日志功能来实现至少
CallerMemberName
功能。它可以使用到.NET 2.0,添加和删除日志非常容易,不像删除代码中的单行。

不,C#没有宏预处理器或任何元编程功能,因此在整个语言中没有“编译时”解决方案。但是,如果必须的话,您可以使用第三方宏语言,但这当然会使构建过程复杂化,VisualStudio不会只知道如何自己构建它

如果需要,甚至可以使用C预处理器。(假设使用MSVC编译器)

  • cl.exe
    是C编译器
  • /TC
    告诉C编译器将所有文件视为C源文件,不管其扩展名如何
  • /P
    告诉C编译器只预处理文件,不要编译它
  • /C
    保留注释
  • /EP
    阻止编译器生成C编译器无法理解的行指令

这将允许您在C程序中使用
#include
#define
#if
以及
(文件)
(行)
),但您必须再次设置Visual Studio来执行此额外的编译步骤,或者使用不同的构建系统。

注意事项:这不是对OP的回答。我知道这一点。但是人们在寻找类似的东西时可能会发现这个页面

  • 这与.NET4无关
  • 这最终仍是一个运行时解决方案
但与2015年相比,C#、.NET Core或.NET 4.5允许:

using System.Runtime.CompilerServices;
using System.Diagnostics;

public static String CurrentLocation(
  [CallerFilePath] string file = null,
  [CallerLineNumber] int lineNumber = 0,
  [CallerMemberName] string method = null)
{
  String location = file;
  if (lineNumber != 0)
  {
    location += "(" + lineNumber.ToString() + ")";
  }
  if (!String.IsNullOrWhiteSpace(method))
  {
    location += ": " + method;
  }
  if (!String.IsNullOrWhiteSpace(location))
  {
    location += ": ";
  }
  return location;
}
[最新用法]

使用类似于:

Console.Error.WriteLine(CurrentLocation() + "some message");


CallerLineNumber
是以运行时方式(作为属性)公开的编译时解决方案。我相信您会发现编译到DLL中的实际行号(很容易验证)。如果你能处理从4.0到4.5的升级,那可能是你最可行的解决方案。CallerLineNumber由编译器在编译时决定,而不是在运行时决定。因此,你不认为在发生错误时只需编写调用堆栈就可以实现你想要的吗?关于我之前的评论,我已经验证过,
CallerLineNumber
会将行号作为常量整数编译到IL中。@Tim Medora No,这会迫使用户将其框架升级到4.5,这在目前是一个不成功的版本。你读过原始帖子了吗?我讨论了这一点,以及为什么我不认为这是一个选项。只有一个源文件具有此日志功能,我们可以从可执行文件的版本中区分源代码的版本。这些都不是例外——我们有用于此的try/catch块。仅仅为了添加日志记录而重新设计代码也没有意义——那将是任人摆布。目前,我正在考虑编写一个编译器预处理器,在文本常量中查找一些字符串,并用行号替换它。这是一个难题,但可能是我的最佳选择。如果您是代码的原始作者,正在进行初始测试,并且您向Visual Studio输出窗口发送了一行格式:
文件(行):…
您可以双击它并转到该行,在该文件中,在项目的当前版本中。这是在编译时了解当前文件和行的最大用途。Marc Gravell的回答对我来说是这样的:@JesseChisholm:对于.NET 4.5/C#5来说也是这样。OP在问题中明确排除了这些版本。@ThomasWeller对于Visual Studio来说是这样的!C/C++/C#。我没有使用VS2017或其他语言进行测试;但在所有以前版本的VS中,它都是有效的。唯一的区别在于如何生成文件
cl.exe /TC /P /C /EP something.cs > something.raw.cs
using System.Runtime.CompilerServices;
using System.Diagnostics;

public static String CurrentLocation(
  [CallerFilePath] string file = null,
  [CallerLineNumber] int lineNumber = 0,
  [CallerMemberName] string method = null)
{
  String location = file;
  if (lineNumber != 0)
  {
    location += "(" + lineNumber.ToString() + ")";
  }
  if (!String.IsNullOrWhiteSpace(method))
  {
    location += ": " + method;
  }
  if (!String.IsNullOrWhiteSpace(location))
  {
    location += ": ";
  }
  return location;
}
Console.Error.WriteLine(CurrentLocation() + "some message");
Debug.WriteLine(CurrentLocation() + "some message");