使用引用变量时,可能会生成以下错误:
- CS0192:字段
readonly
不能用作ref
或out
值(构造函数除外) - CS0199:字段
static readonly
不能用作ref
或out
值(静态构造函数除外) - CS0206:非引用返回属性或索引器不能用作
out
或ref
值 - CS0631:
ref
和out
在此上下文中无效 - CS0767:无法使用指定的类型参数继承接口,因为它会导致方法包含仅在
ref
和out
上存在不同的重载 - CS1510:
ref
或out
值必须是可赋值变量 - CS1605:不能将变量用作
ref
或out
值,因为它为只读 - CS1623:迭代器不能具有
ref
、in
或out
参数 - CS1649:字段
readonly
的成员不能用作ref
或out
值(构造函数除外) - CS1651:静态只读字段的字段不能用作
ref
或out
值(静态构造函数除外) - CS1655:不能将类型字段用作
ref
或out
值 - CS1657:不能将变量用作
ref
或out
值 - CS1741:
ref
或out
参数不能有默认值 - CS1939:无法将范围变量作为
out
或ref
参数传递 - CS1988:异步方法不能具有
ref
、in
或out
参数 - CS7084:无法将 Windows 运行时事件作为
out
或ref
参数传递。 - CS8166:无法通过引用返回参数,因为它不是
ref
参数 - CS8167:无法通过引用返回参数成员,因为它不是
ref
或out
参数 - CS8168:无法通过引用返回局部变量,因为它不是 ref 局部变量
- CS8169:无法通过引用返回局部变量成员,因为它不是 ref 局部变量
- CS8196:对隐式类型的 out 变量的引用不允许出现在同一个参数列表中。
- CS8325:"
await
" 不能在包含ref
条件运算符的表达式中使用 - CS8326:这两个条件运算符的值必须都是 ref 值或者都不是 ref 值
- CS8327:表达式的类型必须正确,才能匹配备用 ref 值
- CS8329:不能将变量用作
ref
或out
值,因为它是只读变量 - CS8330:变量的成员不能用作
ref
或out
值,因为它是只读变量 - CS8331:无法赋值给变量或将其用作
ref
赋值的右侧,因为它是只读变量 - CS8332:无法赋值给变量的成员或将其用作
ref
赋值的右侧,因为它是只读变量 - CS8337:"
ref
" 扩展方法的第一个参数必须是值类型或受结构约束的泛型类型。 - CS8338:扩展方法的第一个 "
in
" 或 "ref readonly
" 参数必须是具体的(非泛型)值类型。 - CS8351:
ref
条件运算符的分支不能引用具有不兼容声明范围的变量 - CS8373:
ref
赋值的左侧必须是 ref 变量。 - CS8374:无法引用赋值,源的转义范围比目标更窄。
- CS8388:
out
变量无法声明为 ref 局部变量 - CS8977:无法在具有 "UnmanagedCallersOnly" 特性的方法的签名中使用 "
ref
"、"in
" 或 "out
"。 - CS9072:析构变量不能声明为 ref 局部变量
- CS9077:无法通过
ref
参数按引用返回参数,它只能在 return 语句中返回 - CS9078:无法通过
ref
参数按引用返回参数的成员,它只能在 return 语句中返回 - CS9079:无法引用赋值,因为源只能通过 return 语句转义当前方法。
- CS9096:无法引用赋值,因为源的值转义范围比目标更广,因此允许通过转义范围比目标更窄的值源进行赋值。
- CS9101:UnscopedRefAttribute 只能应用于结构或虚拟接口实例方法和属性,不能应用于构造函数或仅初始化成员。
- CS9102:UnscopedRefAttribute 不能应用于接口实现,因为实现的成员没有此属性。
- CS9104:不能在异步方法或异步 Lambda 表达式中使用类型的
using
语句资源。 - CS9190:
readonly
修饰符必须在ref
之后指定。 - CS9199:
ref readonly
参数不能具有 Out 特性。
当引用变量被错误地使用时,将生成以下警告:
- CS9085:这会引用赋值变量,但目标比源的转义范围更窄。
- CS9086:
ref
条件运算符的分支引用具有不兼容声明范围的变量 - CS9087:这会按引用返回一个参数,但它不是
ref
参数 - CS9089:这会按引用返回不是
ref
或out
参数的参数成员 - CS9091:这会按引用返回局部变量,但它不是 ref 局部变量
- CS9092:这会按引用返回局部变量的成员,但它不是 ref 局部变量
- CS9093:这会引用赋值,但源只能通过 return 语句对当前方法进行转义。
- CS9094:这会通过
ref
参数按引用返回参数,但它只能在 return 语句中安全返回 - CS9095:这会通过
ref
参数按引用返回参数的成员,但它只能在 return 语句中安全返回 - CS9097:这会引用赋值,但源的值转义范围比目标更广,因此可以通过转义范围比源更窄的值目标进行赋值。
- CS9191:对应于
in
参数的自变量的ref
修饰符等效于in
。请考虑改用in
。 - CS9192:自变量应随
ref
或in
关键字一起传递。 - CS9193:自变量应为变量,因为它被传递给
ref readonly
参数 - CS9195:自变量应随
in
关键字一起传递 - CS9196:参数的引用类型修饰符与替代或实现的成员中相应的参数不匹配。
- CS9197:参数的引用类型修饰符与隐藏的成员中相应的参数不匹配。
- CS9198:参数的引用类型修饰符与目标中相应的参数不匹配。
- CS9200:为
ref readonly
参数指定了默认值,但ref readonly
只应用于引用。请考虑将参数声明为in
。 - CS9201:使用前应引用赋值 ref 字段。
- CS9265: 字段永远不会被重新分配给,并且将始终具有其默认值(null 引用)
这些错误和警告遵循以下主题:
- 语法不正确:声明或用法的语法无效。
- 语言构造,其中
ref
变量无效:某些 C# 习惯用法不允许变量。 通常,这是因为无法可靠地执行 ref 安全分析。 - 需要引用变量时使用了值表达式:用作引用变量的表达式必须是变量,不能是值表达式。
- 引用只读变量的可写引用变量:无法通过可写引用传递对只读变量的引用。
- 违反 ref 安全性:引用变量不能引用具有更窄上下文的变量。 这意味着引用变量可以引用无效的内存。
本文使用“引用变量”一词来作为描述使用 in
、ref readonly
、ref
或 out
修饰符中的一个,或 ref
局部变量、ref struct
中的 ref
字段,或 ref
返回声明的参数的一般性术语。 引用变量引用另一个变量,称为“引用对象”。
语法错误
这些错误表示你对引用变量使用了不正确的语法:
- CS8373:
ref
赋值的左侧必须是 ref 变量。 - CS8388:
out
变量无法声明为 ref 局部变量。 - CS9190:
readonly
修饰符必须在ref
之后指定。
可以通过以下更改之一更正错误:
= ref
运算符的左操作数必须是引用变量。 有关正确语法的详细信息,请参阅参考变量。- 参数修饰符
ref readonly
必须按该顺序排列。readonly ref
不是合法的参数修饰符。 切换单词的顺序。 - 局部变量不能声明为
out
。 要声明本地引用变量,请使用ref
。
引用变量限制
以下错误表示某个引用变量不能用于你已有一个的位置:
- CS0631:
ref
和out
在此上下文中无效 - CS0767:无法使用指定的类型参数继承接口,因为它会导致方法包含仅在
ref
和out
上存在不同的重载 - CS1623:迭代器不能具有
ref
、in
或out
参数 - CS1741:
ref
或out
参数不能有默认值 - CS1939:无法将范围变量作为
out
或ref
参数传递 - CS1988:异步方法不能具有
ref
、in
或out
参数 - CS7084:无法将 Windows 运行时事件作为
out
或ref
参数传递。 - 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
语句资源。 - CS9199:
ref readonly
参数不能具有 Out 特性。
以下警告表示不应使用某个引用变量,并且它可能不安全:
- CS9196:参数的引用类型修饰符与替代或实现的成员中相应的参数不匹配。
- CS9197:参数的引用类型修饰符与隐藏的成员中相应的参数不匹配。
- CS9198:参数的引用类型修饰符与目标中相应的参数不匹配。
- CS9200:为
ref readonly
参数指定了默认值,但ref readonly
只应用于引用。请考虑将参数声明为in
。 - CS9201:使用前应引用赋值 ref 字段。
- CS9265: 字段永远不会被重新分配给,并且将始终具有其默认值(null 引用)
要修复此错误,请在不允许引用变量的位置移除它:
- 从索引器、迭代器和异步方法中移除
in
、ref
和out
参数。 - 移除包含 await 的 ref 条件表达式 (
? :
)。 - 从类型不是值类型或约束为值类型的泛型类型的扩展方法的第一个参数中移除
ref
修饰符。 - 两个[条件运算符表达式]都必须是或两个都不是
ref
变量。 从一个表达式中移除ref
,或将其添加到另一个表达式。 如果它是ref
条件表达式,则两个表达式的类型必须相同。 ref
和out
参数不能有默认值。 移除ref
或out
修饰符,或移除默认值。- 隐式类型的
out
变量声明不能同时出现在同一参数列表中的其他位置。 - 不能在
async
方法 Lambda 表达式的using
语句中放置引用变量。 - LINQ 查询表达式中的范围变量不能通过引用传递。
- 不能将对象析构为引用变量。 将引用变量替换为值变量。
- 无法实现方法重载仅在
ref
和out
上存在差异的多个接口。 例如,一个接口声明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:非引用返回属性或索引器不能用作
out
或ref
值 - CS1510:
ref
或out
值必须是可赋值变量
警告:
- CS9191:对应于
in
参数的自变量的ref
修饰符等效于in
。请考虑改用in
。 - CS9192:自变量应随
ref
或in
关键字一起传递。 - CS9193:自变量应为变量,因为它被传递给
ref readonly
参数 - CS9195:自变量应随
in
关键字一起传递
当使用计算必须使用变量的值的表达式时,编译器会发出这些错误。 必须将该表达式的结果存储在变量中才能使用它。 例如,属性和索引器返回值,而不是变量。 必须将结果存储在变量中,并传递对该变量的引用。
可写引用变量需要可写引用对象
可写引用变量要求引用对象也可写。 以下错误表示变量不可写:
- CS0192:字段
readonly
不能用作ref
或out
值(构造函数除外) - CS0199:字段
static readonly
不能用作ref
或out
值(静态构造函数除外) - CS1605:不能将变量用作
ref
或out
值,因为它为只读 - CS1649:字段
readonly
的成员不能用作ref
或out
值(构造函数除外) - CS1651:字段
static readonly
的字段不能用作ref
或out
值(静态构造函数除外) - CS1655:不能将类型字段用作
ref
或out
值 - CS1657:不能将变量用作
ref
或out
值 - CS8329:不能将变量用作
ref
或out
值,因为它是只读变量 - CS8330:变量的成员不能用作
ref
或out
值,因为它是只读变量 - CS8331:无法赋值给变量或将其用作
ref
赋值的右侧,因为它是只读变量 - CS8332:无法赋值给变量的成员或将其用作
ref
赋值的右侧,因为它是只读变量
不可写的变量的例子包括:
必须复制该值并传递对副本的引用。
ref 安全违规
编译器会跟踪引用对象和引用变量的安全上下文。 当引用变量引用不再有效的引用对象变量时,编译器会在不安全代码中发出错误或警告。 引用对象必须至少具有与引用变量的 ref 安全上下文一样宽的安全上下文。 违反这些安全检查意味着引用变量会访问随机内存而不是引用对象变量。
- CS8166:无法通过引用返回参数,因为它不是
ref
参数 - CS8167:无法通过引用返回参数成员,因为它不是
ref
或out
参数 - CS8168:无法通过引用返回局部变量,因为它不是 ref 局部变量
- CS8169:无法通过引用返回局部变量成员,因为它不是 ref 局部变量
- CS8345:字段或自动实现的属性不能是类型,除非它是
ref struct
的实例成员。 - CS8351:
ref
条件运算符的分支不能引用具有不兼容声明范围的变量 - CS8374:无法引用赋值,源的转义范围比目标更窄。
- CS9077:无法通过
ref
参数按引用返回参数,它只能在 return 语句中返回 - CS9078:无法通过
ref
参数按引用返回参数的成员,它只能在 return 语句中返回 - CS9079:无法将源引用赋值给目标,因为源只能通过 return 语句转义当前方法。
- CS9096:无法将源引用赋值给目标,因为源的值转义范围比目标更广,因此允许通过转义范围比源更窄的值目标进行赋值。
警告:
- CS9085:这会将源引用赋值给目标,但源的转义范围比目标要窄。
- CS9086:ref 条件运算符的分支引用具有不兼容声明范围的变量
- CS9087:这会按引用返回一个参数,但它不是
ref
参数 - CS9089:这会按引用返回不是
ref
或out
参数的参数成员 - CS9091:这会按引用返回局部变量,但它不是 ref 局部变量
- CS9092:这会按引用返回局部变量的成员,但它不是 ref 局部变量
- CS9093:这会将源引用赋值给目标,但源只能通过 return 语句对当前方法进行转义。
- CS9094:这会通过
ref
参数按引用返回参数,但它只能在 return 语句中安全返回 - CS9095:这会通过
ref
参数按引用返回参数的成员,但它只能在 return 语句中安全返回 - CS9097:这会将源引用赋值给目标,但源的值转义范围比目标更广,因此可以通过转义范围比源更窄的值目标进行赋值。
编译器使用静态分析来确定引用对象是否在可以使用引用变量的所有地方有效。 你需要重构代码,使引用对象在引用变量可能引用它的所有位置保持有效。 有关 ref 安全规则的详细信息,请参阅 ref 安全上下文中的 C# 标准。