预处理器错误和警告

编译器在预处理器指令使用不当时生成以下错误:

  • CS1024: 应有预处理器指令
  • CS1025:应为单行注释或行尾
  • CS1027:应有 #endif 指令
  • CS1028: 意外的预处理器指令
  • CS1029: #error:“text”
  • CS1030: #warning:“text”
  • CS1032: 在文件中第一个令牌后无法定义/取消定义预处理器符号
  • CS1038: 预期的 #endregion 指令
  • CS1040: 预处理器指令必须显示为行上的第一个非空格字符
  • CS1517: 预处理器表达式无效
  • CS1560: 为预处理器指令指定的文件名无效。文件名太长或无效的文件名
  • CS1576: 为 #line 指令指定的行号缺失或无效
  • CS1578: 应提供文件名、单行注释或行尾
  • CS1633: 无法识别 #pragma 指令
  • CS1634: 预期禁用或还原
  • CS1635: 无法还原警告“警告代码”,因为它已全局禁用
  • CS1691: “number”不是有效的警告号
  • CS1692: 数字无效
  • CS1694: 为预处理器指令指定的文件名无效。文件名太长或无效的文件名
  • CS1695:#pragma checksum 语法无效;应为 #pragma checksum "filename" "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" "XXXX..."
  • CS1696:应为单行注释或行尾
  • CS1709: 为预处理器指令指定的文件名为空
  • CS7009: 无法在文件的第一个令牌之后使用 #r
  • CS7010: 应有带引号的文件名
  • CS7011: 脚本中仅允许 #r
  • CS8097: #load 仅允许在脚本中
  • CS8098: 在文件中的首个标记后无法使用 #load
  • CS8301: 预处理符号的名称无效;“符号名称”不是有效的标识符
  • CS8938: #line 指令值缺失或范围不足
  • CS8939: #line 指令结束位置必须大于或等于起始位置
  • CS8996: 预处理器指令中不允许原始字符串文本
  • CS9028: #line span 指令需要在第一个括号前、字符偏移前和文件名之前空格
  • CS9297: #: 指令不能放在文件中第一个标记之后
  • CS9298: #: 指令只能在基于文件的应用中使用(-features:FileBasedProgram)
  • CS9299:#: 指令不能在 #if 指令之后
  • CS9314: #! 指令只能在脚本或基于文件的应用中使用
  • CS9378: “#!”必须是文件第一行上的第一个字符

预处理器指令语法无效

  • CS1024: 预期预处理器指令
  • CS1025:应为单行注释或行尾
  • CS1027: 需要 #endif 指令
  • CS1028: 意外的预处理器指令
  • CS1032:在文件中的第一个标记之后,无法定义/取消定义预处理器符号
  • CS1038:应为 #endregion 指令
  • CS1040: 预处理器指令必须显示为行上的第一个非空格字符
  • CS1517: 预处理器表达式无效
  • CS1633: 无法识别 #pragma 指令
  • CS1696: 预期出现单行注释或行末注释
  • CS8996: 预处理器指令中不允许原始字符串文本

这些错误指示你对 预处理器指令使用了无效的语法。 常见原因包括:

  • 在 # 之后使用无法识别的指令(CS1024、CS1633)。
  • 在指令行中包含多行注释(适用于 CS1025 和 CS1696)。
  • 在意外位置使用指令 (CS1028)。
  • 缺少所需的匹配指令(CS1027、CS1038)。
  • 将 #define 或 #undef 指令放在文件中的第一个标记之后 (CS1032)。
  • 未将指令放置为行上的第一个标记 (CS1040)。
  • 在条件编译中使用无效的表达式(CS1517)。
  • 在预处理器指令中使用原始字符串文本(CS8996)。

CS1024 示例 - 需要预处理器指令:

#import System   // CS1024 - "import" is not a valid directive

CS1025 示例 - 应为单行注释或行尾:

#if true /* hello  
*/   // CS1025 - multiline comment not allowed
#endif

CS1027 示例 - 预计需要 #endif 指令:

#if true   // CS1027 - missing #endif
class Test { }

CS1028 示例 - 意外的预处理器指令:

#endif   // CS1028 - no matching #if

CS1032 示例 - #define 和 #undef 预处理器指令必须出现在其他令牌之前:

class Test { }
#define X   // CS1032 - directive appears after the first token

若要修复此错误,请在文件的第一个令牌之前放置所有 #define 和 #undef 指令:

#define X
#undef Y
class Test { }

CS1038 示例 - 需要 #endregion 指令:

#region testing
class Test { }
// CS1038 - missing #endregion

CS1040 示例 - 预处理器指令必须显示为第一个非空格字符:

/* Comment */ #define X   // CS1040 - directive not first on line

CS1517 示例 - 预处理器表达式无效:

#if 1           // CS1517 - numeric literals not allowed
#endif
#if ~symbol     // CS1517 - bitwise operators not allowed  
#endif

CS1633 示例 - 无法识别 #pragma 指令:

#pragma unknown  // CS1633 - "unknown" is not a valid pragma

CS8996 示例 - 预处理器指令中不允许原始字符串文本:

// CS8996.cs
#pragma checksum """raw_string""" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "hash"  // CS8996
class Test { }

若要修复此错误,请使用常规字符串文本:

#pragma checksum "filename.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "hash"  // OK
class Test { }

若要修复这些错误,请确保预处理器指令遵循 预处理器指令文档中介绍的正确语法规则。

无效的预处理器符号名称

  • CS8301: 预处理符号的名称无效;“符号名称”不是有效的标识符

以编程方式创建 CSharpParseOptions 时,请为每个条件编译符号提供一个标识符形状的名称。 第一个字符必须在 C# 标识符的开头有效,其余字符必须是有效的标识符字符。 Roslyn 还接受关键字文本作为符号名称,但不添加 @ 前缀。 不要包含空格、标点符号(如 . 或 -)、赋值(如 FEATURE=1)或完整的条件表达式。

预处理符号仅记录其名称是否定义。 它不存储值。 通过 DefineConstants 项目属性或 -define 编译器选项提供的无效名称将改为产生 CS2029;请参阅 DefineConstants。

#error 和 #warning 指令错误

  • CS1029: #error:“text”
  • CS1030:#warning: 'text'
  • CS1634: 预期禁用或还原
  • CS1635: 无法还原警告“警告代码”,因为它已全局禁用
  • CS1691: “number”不是有效的警告号
  • CS1692: 数字无效

当编译器处理#error和#warning#pragma warning指令时,会发生这些错误。 这些指令允许在编译和控制警告行为期间生成自定义错误和警告消息。

CS1029 显示使用 #error 指令定义的错误的文本:

// CS1029.cs
class Sample
{
   static void Main()
   {
      #error Let's give an error here   // CS1029
   }
}

编译产生以下输出:

example.cs(9,8): error CS1029: #error: 'Let's give an error here   // CS1029  '

CS1030 显示使用 #warning 指令定义的警告文本:

// CS1030.cs
class Sample
{
   static void Main()
   {
      #warning Let's give a warning here
   }
}

编译产生以下输出:

example.cs(6,16): warning CS1030: #warning: 'Let's give a warning here'

当 #pragma warning 子句格式错误时(例如省略了 disable 或 restore),会发生 CS1634:

// CS1634.cs
// compile with: /W:1

#pragma warning   // CS1634
// Try this instead:
// #pragma warning disable 0219

class MyClass
{
  public static void Main()
  {
  }
}

CS1635 当您使用命令行选项或项目设置来全局禁用警告时发生,但使用/nowarn试图恢复该警告:

// CS1635.cs
// compile with: /w:1 /nowarn:162

enum MyEnum {one=1,two=2,three=3};

class MyClass
{
    public static void Main()
    {
#pragma warning disable 162

    if (MyEnum.three == MyEnum.two)
        System.Console.WriteLine("Duplicate");

#pragma warning restore 162  // CS1635
    }
}

当传递给指令的数字不是有效的警告号时,会发生 #pragma warning:

// CS1691.cs
public class C
{
    int i = 1;
    public static void Main()
    {
        C myC = new C();
#pragma warning disable 151  // CS1691
// Try the following line instead:
// #pragma warning disable 1645
        myC.i++;
#pragma warning restore 151  // CS1691
// Try the following line instead:
// #pragma warning restore 1645
    }
}

CS1692 发生在预处理器指令中的数字(如 #pragma 且 #line 无效)时,因为它太大、格式错误或包含非法字符:

// CS1692.cs

#pragma warning disable a  // CS1692
// Try this instead:
// #pragma warning disable 1691

class A
{
    static void Main()
    {
    }
}

这些指令对于条件编译方案非常有用,你希望提醒开发人员有关代码中的特定条件,或控制编译期间显示哪些警告。 有关使用这些指令的详细信息,请参阅 预处理器指令文档 和 #pragma 警告。

#line 和文件指令错误

  • CS1560: 为预处理器指令指定的文件名无效。文件名太长或无效。
  • CS1576: 为 #line 指令指定的行号缺失或无效。
  • CS1578: 需要文件名、单行注释或行尾。
  • CS1694: 为预处理器指令指定的文件名无效。文件名太长或无效。
  • CS1695:无效的 #pragma checksum 语法;应为 #pragma checksum "filename" "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" "XXXX..."。
  • CS1709: 为预处理器指令指定的文件名为空。
  • CS8938: #line 指令值缺失或范围不足。
  • CS8939: #line 指令结束位置必须大于或等于起始位置。
  • CS9028: #line span 指令要求在第一个括号前、字符偏移前和文件名之前有空格。

这些错误表示指令或与文件相关的预处理器指令的用法#line不正确。 常见原因包括:

  • 无效或缺少文件名(CS1560、CS1694、CS1709)。
  • 行号格式或值不正确(CS1576、CS8938、CS8939)。
  • 缺少文件名和注释的正确语法(CS1578)。
  • 语法格式错误 #pragma checksum(CS1695)。
  • 跨度指令中的 #line 间距不正确(CS9028)。

CS1560/CS1694 示例 - 指定的文件名无效:

#line 100 "MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890MyFile1234567890.txt"   // CS1560/CS1694 - filename too long

CS1576 示例 - 行号缺失或无效:

#line "abc.sc"         // CS1576 - missing line number
#line abc "file.cs"    // CS1576 - invalid line number format

CS1578 示例 - 应为文件名、注释或行尾:

#line 101 abc.cs   // CS1578 - filename not quoted

CS1695 示例 - #pragma 校验和语法无效:

#pragma checksum "12345"  // CS1695 - missing GUID and checksum

CS1709 示例 - 空文件名:

#pragma checksum "" "{406EA660-64CF-4C82-B6F0-42D48172A799}" ""  // CS1709 - empty filename

CS8938 示例 - #line 指令值缺失或范围不足:

#line   // CS8938 - missing value
#line 0  // CS8938 - out of range (must be 1-16,707,566)

CS8939 示例 - #line 结束位置错误:

#line (1, 10) - (1, 5) "file.cs"  // CS8939 - end column < start column

CS9028 示例 - #line span 指令间距:

#line(1, 1) - (1, 10)"file.cs"  // CS9028 - missing spaces

若要修复这些错误,请确保指令 #line 和与文件相关的预处理器指令遵循正确的语法,如 预处理器指令文档中所述。

基于文件的应用指令使用不正确

  • CS9297:#:指令不能位于文件中第一个标记之后
  • CS9298: #: 指令只能在基于文件的应用中使用(-features:FileBasedProgram)
  • CS9299:#: 指令不能位于 #if 指令之后
  • CS9314: #! 指令只能在脚本或基于文件的应用中使用
  • CS9378: “#!”必须是文件第一行上的第一个字符

这些错误指示错误使用了 #: 或 #! 指令。 若要详细了解这些指令的语法,请参阅基于文件的应用的部分中有关 预处理器指令 的文章。 或者,可以按照基于文件的应用的 教程 来浏览基于文件的应用。

Shebang (#!) 为脚本或基于文件的应用选择可执行文件。 将其放在第一行的第一个字符处,在任何空白字符、注释或空行之前(CS9378);请参阅 基于文件的应用指令指南。

文件包含script.cs指令

以下错误指示 C# 脚本指令的使用或放置不正确:

  • CS7009: 无法在文件中的第一个令牌后使用 #r
  • CS7010: 应有带引号的文件名
  • CS7011: 脚本中仅允许 #r
  • CS8097: 脚本中仅允许 #load
  • CS8098:无法在文件中的第一个标记之后使用 #load

在 C# 脚本(.csx)中, #load 令牌后面的指令生成 CS8098:

System.Console.WriteLine("This is the first token.");
#load "helpers.csx" // CS8098

若要修复 CS8098,请在脚本中的每个令牌之前移动每个 #load 指令:

#load "helpers.csx"
System.Console.WriteLine("The directive precedes the first token.");

在常规 C# 源文件(.cs)中,不允许使用 #load。 相关条件生成 CS8097,而不是 CS8098。 从常规源文件中删除 #load 。