如何针对特定文件禁用特定编译器警告

16

背景

我正在开发一个小型编码项目,将要销售给其他公司。我需要创建一些文档来进行说明,所以我决定使用Sandcastle。在下载和安装过程中花费了太长时间后,我终于让它运行起来了,并注意到任何没有注释的公共方法或类都会显示红色文本,说明缺少注释。于是我安装了Ghostdoc来加快我的注释速度。这打开了缺少xml注释的编译器警告,这很棒,因为我现在有了一个需要注释的列表。

问题

我的其中一个代码文件是自动生成的文件,包含约3000个编译器警告。我需要能够跳过该文件创建任何“缺少Xml注释”的编译器警告。我从帖子中获得以下信息:

  • 我知道可以关闭项目的编译器警告,但项目中还有其他应该具有编译器警告的文件。
  • 我知道可以使用#pragma warning disable 1591来删除编译器警告,但该文件是自动生成的,我真的不想每次手动重新添加它。
  • 我知道可以添加一个空注释,但再次强调,我真的不想每次重新生成文件时都要重新添加它。
  • 我可以将文件移出到自己的项目中,因为它是命名空间中唯一的类,然后删除XML注释要求,但我不希望客户需要处理另一个dll。
  • 这些类是部分类,所以我考虑尝试找到一种方法在部分类中添加#pragma警告禁用,但即使这是可能的,仍然会有枚举类型抛出警告。

如何告诉VS忽略单个文件的特定类型的警告?


同意@Paolo的观点 - 如果这些类不应该在外部可见,尝试找到一种方法来防止它们被公开。如果它们应该是公开可见的,则创建一个带有部分类和部分方法的类,在其中添加XML文档。 - Damien_The_Unbeliever
@Damien_The_Unbeliever,该文件实际上有数百个枚举。据我所知,没有办法创建部分枚举。此外,如果一个部分类在一个文件中定义了一个方法,我不能在另一个文件中再次定义它,对吗? - Daryl
请将您的解决方案发布为答案,而不是问题的一部分。 - casperOne
3个回答

3

我想到了两种可能性:

  1. 你能否再创建另一个类来导入自动生成的 .cs 文件?这个包装类有 pragma,只需导入自动生成的类。
  2. 编写一个 Perl 脚本(或简单的 C# 程序),在文件生成后且在 .cs 文件编译之前作为构建事件调用。

我不是 Perl 方面的专家,所以我猜一个作为预编译事件运行的 C# 程序可能会起作用…… 我会试一试。 - Daryl

3
如果生成的类不应该对用户可见,你可以检查生成工具是否有将类生成为 internal 而不是 public 的选项。
如果你的生成代码是一个 Web 服务引用,创建引用时有一个选项可以指定这一点(在“添加服务引用”对话框中,选择高级 -> 生成类的访问级别)。
否则,你可以尝试找到一种自动将生成代码中的类型从 public 更改为 internal 的方法。

公共/内部的想法不错,但必须是公共的。这是使用crmsrvutil.exe生成的。 - Daryl

1

编辑:我的解决方案

我采用了David Thielen的建议,创建了一个C#程序,将#pragma warning disable消息插入到我的自动生成的文件中。理想情况下,我会在文件生成后调用它作为后操作,但现在预编译命令就足够了,因为我的语句将是文件中的第一行之一,它只需要读取几行,看到禁用语句已经存在,并退出,所以不应该拖慢构建速度。以下是我的程序,供大家欣赏! :)

/// <summary>
/// Addes #pragma warning disable messages to source code as part of a prebuild to ignore warnings.
/// Primarly used for autogenerated classes that may contain some compiler warnings by default
/// </summary>
public class Program
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="args">
    /// [0] - file to edit
    /// [1] - line number to insert / edit warning disable at
    /// [2+] - warnings numbers to disable</param>
    static void Main(string[] args)
    {
        // Preconditions
        if (args.Length < 2)
        {
            throw new ArgumentException(String.Format("Unexpected number of parameters.{0}Parameters should be [0] - file to edit{0}[1] - line number to insert / edit warning disable at{0}[2+] - warnings numbers to disable", Environment.NewLine));
        }
        else if (args.Length == 2) { return; }

        // Valid number of args, validate arguments
        string filePath = args[0];
        long lineNumber;

        if(!long.TryParse(args[1], out lineNumber)){
            throw new InvalidCastException("Unable to cast \"" + args[1] + "\" to a long");
        }

        string[] compilerWarningNumbers = new string[args.Length - 2];
        Array.ConstrainedCopy(args, 2, compilerWarningNumbers, 0, compilerWarningNumbers.Length);

        // File Name and line number are valid, perform search and replace
        AddOrUpdateCompilerWarningDisabler(filePath, lineNumber, String.Join(",", compilerWarningNumbers));

    }

    private const string TEMP_FILE_POSTFIX = ".CompilerWarningDisabler.txt";
    public static void AddOrUpdateCompilerWarningDisabler(string filePath, long lineNumber, string compilerWarningNumberCSV)
    {
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException("File path not found!", filePath);
        }

        // Set Clear Readonly Flag
        FileInfo fileInfo = new FileInfo(filePath);
        bool isReadOnly = fileInfo.IsReadOnly;

        // Get Temp File Name and Delete if it already exists
        string tempFile = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + TEMP_FILE_POSTFIX);
        File.Delete(tempFile);

        // Read from the target file and write to a new file.
        int currentLine = 1;
        string line;
        string textToWrite = "#pragma warning disable " + compilerWarningNumberCSV;
        try
        {
            using (StreamReader reader = new StreamReader(filePath))
            using (StreamWriter writer = new StreamWriter(tempFile))
            {
                while ((line = reader.ReadLine()) != null)
                {
                    if (currentLine == lineNumber)
                    {
                        if (line.StartsWith("#pragma warning disable"))
                        {
                            if (line == textToWrite)
                            {
                                // Nothing has changed, don't bother copying file
                                return;
                            }
                            else
                            {
                                line = textToWrite;
                            }
                        }
                        else
                        {
                            writer.WriteLine(textToWrite);
                            writer.WriteLine(line);
                        }
                    }
                    else
                    {
                        writer.WriteLine(line);
                    }
                    currentLine++;
                }

                if (currentLine == lineNumber)
                {
                    writer.WriteLine(textToWrite);
                }

                if (currentLine < lineNumber)
                {
                    throw new InvalidDataException("File " + filePath + " does not contain line number " + lineNumber);
                }
            }

            // This could potentially delete the source file, but this should be messing with autogenerated files, so even if it does happen, it shouldn't be to hard to get it back
            if (isReadOnly)
            {
                fileInfo.IsReadOnly = false;
            }
            File.Delete(filePath);
            File.Move(tempFile, filePath);
            if (isReadOnly)
            {
                new FileInfo(filePath).IsReadOnly = true;
            }
        }
        finally
        {
            File.Delete(tempFile);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接