与引用参数、变量和返回关联的错误和警告

使用引用变量时,可能会生成以下错误:

  • CS0192字段 readonly 不能用作 refout 值(构造函数除外)
  • CS0199字段 static readonly 不能用作 refout 值(静态构造函数除外)
  • CS0206非引用返回属性或索引器不能用作 outref
  • CS0631refout 在此上下文中无效
  • CS0767无法使用指定的类型参数继承接口,因为它会导致方法包含仅在 refout 上存在不同的重载
  • CS1510refout 值必须是可赋值变量
  • CS1605不能将变量用作 refout 值,因为它为只读
  • CS1623迭代器不能具有 refinout 参数
  • CS1649字段 readonly 的成员不能用作 refout 值(构造函数除外)
  • CS1651静态只读字段的字段不能用作 refout 值(静态构造函数除外)
  • CS1655不能将类型字段用作 refout
  • CS1657不能将变量用作 refout
  • CS1741refout 参数不能有默认值
  • CS1939无法将范围变量作为 outref 参数传递
  • CS1988异步方法不能具有 refinout 参数
  • CS7084无法将 Windows 运行时事件作为 outref 参数传递。
  • CS8166无法通过引用返回参数,因为它不是 ref 参数
  • CS8167无法通过引用返回参数成员,因为它不是 refout 参数
  • CS8168无法通过引用返回局部变量,因为它不是 ref 局部变量
  • CS8169无法通过引用返回局部变量成员,因为它不是 ref 局部变量
  • CS8196:对隐式类型的 out 变量的引用不允许出现在同一个参数列表中。
  • CS8325"await" 不能在包含 ref 条件运算符的表达式中使用
  • CS8326这两个条件运算符的值必须都是 ref 值或者都不是 ref 值
  • CS8327表达式的类型必须正确,才能匹配备用 ref 值
  • CS8329不能将变量用作 refout 值,因为它是只读变量
  • CS8330变量的成员不能用作 refout 值,因为它是只读变量
  • CS8331无法赋值给变量或将其用作 ref 赋值的右侧,因为它是只读变量
  • CS8332无法赋值给变量的成员或将其用作 ref 赋值的右侧,因为它是只读变量
  • CS8337"ref" 扩展方法的第一个参数必须是值类型或受结构约束的泛型类型。
  • CS8338扩展方法的第一个 "in" 或 "ref readonly" 参数必须是具体的(非泛型)值类型。
  • CS8351ref 条件运算符的分支不能引用具有不兼容声明范围的变量
  • CS8373ref 赋值的左侧必须是 ref 变量。
  • CS8374无法引用赋值,源的转义范围比目标更窄。
  • CS8388out 变量无法声明为 ref 局部变量
  • CS8977无法在具有 "UnmanagedCallersOnly" 特性的方法的签名中使用 "ref"、"in" 或 "out"。
  • CS9072析构变量不能声明为 ref 局部变量
  • CS9077无法通过 ref 参数按引用返回参数,它只能在 return 语句中返回
  • CS9078无法通过 ref 参数按引用返回参数的成员,它只能在 return 语句中返回
  • CS9079无法引用赋值,因为源只能通过 return 语句转义当前方法。
  • CS9096无法引用赋值,因为源的值转义范围比目标更广,因此允许通过转义范围比目标更窄的值源进行赋值。
  • CS9101:UnscopedRefAttribute 只能应用于结构或虚拟接口实例方法和属性,不能应用于构造函数或仅初始化成员。
  • CS9102:UnscopedRefAttribute 不能应用于接口实现,因为实现的成员没有此属性
  • CS9104不能在异步方法或异步 Lambda 表达式中使用类型的 using 语句资源。
  • CS9190readonly 修饰符必须在 ref 之后指定。
  • CS9199ref readonly 参数不能具有 Out 特性。

当引用变量被错误地使用时,将生成以下警告:

  • CS9085这会引用赋值变量,但目标比源的转义范围更窄。
  • CS9086ref 条件运算符的分支引用具有不兼容声明范围的变量
  • CS9087这会按引用返回一个参数,但它不是 ref 参数
  • CS9089这会按引用返回不是 refout 参数的参数成员
  • CS9091这会按引用返回局部变量,但它不是 ref 局部变量
  • CS9092这会按引用返回局部变量的成员,但它不是 ref 局部变量
  • CS9093这会引用赋值,但源只能通过 return 语句对当前方法进行转义。
  • CS9094这会通过 ref 参数按引用返回参数,但它只能在 return 语句中安全返回
  • CS9095这会通过 ref 参数按引用返回参数的成员,但它只能在 return 语句中安全返回
  • CS9097这会引用赋值,但源的值转义范围比目标更广,因此可以通过转义范围比源更窄的值目标进行赋值。
  • CS9191对应于 in 参数的自变量的 ref 修饰符等效于 in。请考虑改用 in
  • CS9192自变量应随 refin 关键字一起传递。
  • CS9193自变量应为变量,因为它被传递给 ref readonly 参数
  • CS9195自变量应随 in 关键字一起传递
  • CS9196参数的引用类型修饰符与替代或实现的成员中相应的参数不匹配。
  • CS9197参数的引用类型修饰符与隐藏的成员中相应的参数不匹配。
  • CS9198参数的引用类型修饰符与目标中相应的参数不匹配。
  • CS9200ref readonly 参数指定了默认值,但 ref readonly 只应用于引用。请考虑将参数声明为 in
  • CS9201使用前应引用赋值 ref 字段。
  • CS9265字段永远不会被重新分配给,并且将始终具有其默认值(null 引用)

这些错误和警告遵循以下主题:

本文使用“引用变量”一词来作为描述使用 inref readonlyrefout 修饰符中的一个,或 ref 局部变量、ref struct 中的 ref 字段,或 ref 返回声明的参数的一般性术语。 引用变量引用另一个变量,称为“引用对象”。

语法错误

这些错误表示你对引用变量使用了不正确的语法:

  • CS8373ref 赋值的左侧必须是 ref 变量。
  • CS8388out 变量无法声明为 ref 局部变量。
  • CS9190readonly 修饰符必须在 ref 之后指定。

可以通过以下更改之一更正错误:

  • = ref 运算符的左操作数必须是引用变量。 有关正确语法的详细信息,请参阅参考变量
  • 参数修饰符 ref readonly 必须按该顺序排列。 readonly ref 不是合法的参数修饰符。 切换单词的顺序。
  • 局部变量不能声明为 out。 要声明本地引用变量,请使用 ref

引用变量限制

以下错误表示某个引用变量不能用于你已有一个的位置:

  • CS0631refout 在此上下文中无效
  • CS0767无法使用指定的类型参数继承接口,因为它会导致方法包含仅在 refout 上存在不同的重载
  • CS1623迭代器不能具有 refinout 参数
  • CS1741refout 参数不能有默认值
  • CS1939无法将范围变量作为 outref 参数传递
  • CS1988异步方法不能具有 refinout 参数
  • CS7084无法将 Windows 运行时事件作为 outref 参数传递。
  • CS8196:对隐式类型的 out 变量的引用不允许出现在同一个参数列表中
  • CS8325"await" 不能在包含 ref 条件运算符的表达式中使用
  • CS8326这两个条件运算符的值必须都是 ref 值或者都不是 ref 值
  • CS8327表达式的类型必须正确,才能匹配备用 ref 值
  • CS8337"ref" 扩展方法的第一个参数必须是值类型或受结构约束的泛型类型。
  • CS8338扩展方法的第一个 "in" 或 "ref readonly" 参数必须是具体的(非泛型)值类型。
  • CS8977无法在具有 "UnmanagedCallersOnly" 特性的方法的签名中使用 "ref"、"in" 或 "out"。
  • CS9072析构变量不能声明为 ref 局部变量
  • CS9104不能在异步方法或异步 Lambda 表达式中使用类型的 using 语句资源。
  • CS9199ref readonly 参数不能具有 Out 特性。

以下警告表示不应使用某个引用变量,并且它可能不安全:

  • CS9196参数的引用类型修饰符与替代或实现的成员中相应的参数不匹配。
  • CS9197参数的引用类型修饰符与隐藏的成员中相应的参数不匹配。
  • CS9198参数的引用类型修饰符与目标中相应的参数不匹配。
  • CS9200ref readonly 参数指定了默认值,但 ref readonly 只应用于引用。请考虑将参数声明为 in
  • CS9201使用前应引用赋值 ref 字段。
  • CS9265字段永远不会被重新分配给,并且将始终具有其默认值(null 引用)

要修复此错误,请在不允许引用变量的位置移除它:

  • 索引器迭代器异步方法中移除 inrefout 参数。
  • 移除包含 awaitref 条件表达式 (? :)。
  • 从类型不是值类型或约束为值类型的泛型类型的扩展方法的第一个参数中移除 ref 修饰符。
  • 两个[条件运算符表达式]都必须是或两个都不是 ref 变量。 从一个表达式中移除 ref,或将其添加到另一个表达式。 如果它是 ref 条件表达式,则两个表达式的类型必须相同。
  • refout 参数不能有默认值。 移除 refout 修饰符,或移除默认值。
  • 隐式类型的 out 变量声明不能同时出现在同一参数列表中的其他位置。
  • 不能在 async 方法 Lambda 表达式的 using 语句中放置引用变量。
  • LINQ 查询表达式中的范围变量不能通过引用传递。
  • 不能将对象析构为引用变量。 将引用变量替换为值变量。
  • 无法实现方法重载仅在 refout 上存在差异的多个接口。 例如,一个接口声明 void M(ref int i),另一个接口声明 void M(out int i)。 类无法实现这两个接口,因为方法无法区分。 只能实现其中一个接口。
  • 使用 System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute 特性化的方法不能使用引用参数。
  • 无法将 Windows 运行时事件作为引用变量传递。
  • ref readonly 参数不能在远程处理 API 中应用 System.Runtime.InteropServices.OutAttribute
  • ref在构造函数中或字段初始值设定项中初始化字段。

unscoped ref 限制

某些位置不允许 ref 参数的 unscoped 限定符:

  • CS9101:UnscopedRefAttribute 只能应用于结构实例或虚拟接口方法和属性,不能应用于构造函数或仅初始化成员
  • CS9102:UnscopedRefAttribute 不能应用于接口实现,因为实现的成员没有此属性

必须移除参数声明上导致错误的 unscoped 修饰符。

引用变量需要引用对象

必须向引用参数、引用返回或 ref 本地赋值提供一个变量作为自变量:

  • CS0206非引用返回属性或索引器不能用作 outref
  • CS1510refout 值必须是可赋值变量

警告:

  • CS9191对应于 in 参数的自变量的 ref 修饰符等效于 in。请考虑改用 in
  • CS9192自变量应随 refin 关键字一起传递。
  • CS9193自变量应为变量,因为它被传递给 ref readonly 参数
  • CS9195自变量应随 in 关键字一起传递

当使用计算必须使用变量的值的表达式时,编译器会发出这些错误。 必须将该表达式的结果存储在变量中才能使用它。 例如,属性和索引器返回值,而不是变量。 必须将结果存储在变量中,并传递对该变量的引用。

可写引用变量需要可写引用对象

可写引用变量要求引用对象也可写。 以下错误表示变量不可写:

  • CS0192字段 readonly 不能用作 refout 值(构造函数除外)
  • CS0199字段 static readonly 不能用作 refout 值(静态构造函数除外)
  • CS1605不能将变量用作 refout 值,因为它为只读
  • CS1649字段 readonly 的成员不能用作 refout 值(构造函数除外)
  • CS1651字段 static readonly 的字段不能用作 refout 值(静态构造函数除外)
  • CS1655不能将类型字段用作 refout
  • CS1657不能将变量用作 refout
  • CS8329不能将变量用作 refout 值,因为它是只读变量
  • CS8330变量的成员不能用作 refout 值,因为它是只读变量
  • CS8331无法赋值给变量或将其用作 ref 赋值的右侧,因为它是只读变量
  • CS8332无法赋值给变量的成员或将其用作 ref 赋值的右侧,因为它是只读变量

不可写的变量的例子包括:

  • 只读字段,包括实例字段和静态字段。
  • readonly 字段的成员。
  • this 变量。
  • foreach 迭代变量
  • using 变量或 fixed 变量。

必须复制该值并传递对副本的引用。

ref 安全违规

编译器会跟踪引用对象和引用变量的安全上下文。 当引用变量引用不再有效的引用对象变量时,编译器会在不安全代码中发出错误或警告。 引用对象必须至少具有与引用变量的 ref 安全上下文一样宽的安全上下文。 违反这些安全检查意味着引用变量会访问随机内存而不是引用对象变量。

  • CS8166无法通过引用返回参数,因为它不是 ref 参数
  • CS8167无法通过引用返回参数成员,因为它不是 refout 参数
  • CS8168无法通过引用返回局部变量,因为它不是 ref 局部变量
  • CS8169无法通过引用返回局部变量成员,因为它不是 ref 局部变量
  • CS8345字段或自动实现的属性不能是类型,除非它是 ref struct 的实例成员。
  • CS8351ref 条件运算符的分支不能引用具有不兼容声明范围的变量
  • CS8374无法引用赋值,源的转义范围比目标更窄。
  • CS9077无法通过 ref 参数按引用返回参数,它只能在 return 语句中返回
  • CS9078无法通过 ref 参数按引用返回参数的成员,它只能在 return 语句中返回
  • CS9079无法将源引用赋值给目标,因为源只能通过 return 语句转义当前方法。
  • CS9096无法将源引用赋值给目标,因为源的值转义范围比目标更广,因此允许通过转义范围比源更窄的值目标进行赋值。

警告:

  • CS9085这会将源引用赋值给目标,但源的转义范围比目标要窄。
  • CS9086ref 条件运算符的分支引用具有不兼容声明范围的变量
  • CS9087这会按引用返回一个参数,但它不是 ref 参数
  • CS9089这会按引用返回不是 refout 参数的参数成员
  • CS9091这会按引用返回局部变量,但它不是 ref 局部变量
  • CS9092这会按引用返回局部变量的成员,但它不是 ref 局部变量
  • CS9093这会将源引用赋值给目标,但源只能通过 return 语句对当前方法进行转义。
  • CS9094这会通过 ref 参数按引用返回参数,但它只能在 return 语句中安全返回
  • CS9095这会通过 ref 参数按引用返回参数的成员,但它只能在 return 语句中安全返回
  • CS9097这会将源引用赋值给目标,但源的值转义范围比目标更广,因此可以通过转义范围比源更窄的值目标进行赋值。

编译器使用静态分析来确定引用对象是否在可以使用引用变量的所有地方有效。 你需要重构代码,使引用对象在引用变量可能引用它的所有位置保持有效。 有关 ref 安全规则的详细信息,请参阅 ref 安全上下文中的 C# 标准。