如何获得 File.OpenText 到 return 不可为空的 StreamReader
How to get File.OpenText to return non-nullable StreamReader
考虑以下因素:
var lines = new List<string>();
string path = "FileName.txt";
var reader = File.OpenText(path);
while (!reader.EndOfStream)
{
lines.Add(reader.ReadLine());
}
将 Nullable
标志设置为 enable
时,在 csproj 中,reader
是一个 StreamReader?
,会给出 Possible null reference argument for parameter 'item'
编译器警告。即使我明确地将 reader
设置为 StreamReader
,问题仍然存在。
有没有办法在不关闭 Nullable
的情况下绕过这个警告?
我认为,问题描述中包含的警告并不完整。我重现了这个问题并得到了下一个编译器警告:CS8604 Possible null reference argument for parameter 'item' in 'void List<string>.Add(string item)
。警告出现在下一行
lines.Add(reader.ReadLine());
因为 List<string> lines
是不可为空的 string
值的列表,并且方法 StreamReader.ReadLine()
可以 return 为空 string?
(参见 reference source).因此,在上面的代码行中,这些是尝试将 null
字符串值添加到不可为 null 的字符串列表中。
要解决此问题,您可以使用以下任一方法:
Use null-forgiving operator. 你肯定知道表达式的结果 reader.ReadLine()
不能是 null
因为它是在未到达流末尾时执行的。因此,您可以使用 null-forgiving 运算符来抑制警告:
lines.Add(reader.ReadLine()!);
检查表达式reader.ReadLine()
的结果是否为空。如果使用下一个警告将消失的代码:
string? line = reader.ReadLine();
if (line != null)
lines.Add(line);
更新
正如@IanRingrose 在评论中指出的那样,可以在循环中使用条件 line != null
而不是条件 !reader.EndOfStream()
。使用这样的条件解可以更清楚:
string? line;
while ((line = reader.ReadLine()) != null)
{
lines.Add(line);
}
现在我们不需要在循环体中使用 null-forgiving 运算符或附加条件。
回答您关于 reader 本身的可空性的具体问题:reader
是一个 StreamReader?
,因为 NRT 决定使用 var
将推断变量的类型为 nullable.
nullable implicitly typed local variables
var
infers an annotated type for reference types. For instance, in var s = "";
the var
is inferred as string?
.
language design notes 解释这个决定。最终他们得出结论:
Make var
have a nullable annotated type and infer the flow type as normal.
想法是,由于没有 var?
的语法,该类型被推断为最不严格的类型(即,允许稍后对变量进行 null
赋值)。最终,可空性 应该 通过流分析进行跟踪。
也就是说,已知使用 OpenText
总是 return 一个非 null
对象(否则它会抛出)并且有一个 non-nullable return type。要解决您的问题,只需将您的变量直接声明为 StreamReader
:
StreamReader reader = File.OpenText(path);
正如其他答案所指出的,我认为您对实际错误及其发生位置感到困惑。 “项目”唯一会出现的地方是调用 List<>.Add
时。当然,这是因为 StreamReader.ReadLine
可以 return null
而您的列表声明为 List<string>
而不是 List<string?>
您的选择是:
- 更改列表的类型(可能不会)
- 使用 null-forgiving 运算符
reader.ReadLine()!
(也许,但只有在保证的情况下)
- 使用局部变量并在添加到列表之前添加对
null
的检查(直接或通过修改循环条件来执行赋值和空检查)
您可以将所有代码减少到只有两行 Nullable-friendly 行:
string path = "FileName.txt";
var lines = File.ReadLines(path).ToList();
考虑以下因素:
var lines = new List<string>();
string path = "FileName.txt";
var reader = File.OpenText(path);
while (!reader.EndOfStream)
{
lines.Add(reader.ReadLine());
}
将 Nullable
标志设置为 enable
时,在 csproj 中,reader
是一个 StreamReader?
,会给出 Possible null reference argument for parameter 'item'
编译器警告。即使我明确地将 reader
设置为 StreamReader
,问题仍然存在。
有没有办法在不关闭 Nullable
的情况下绕过这个警告?
我认为,问题描述中包含的警告并不完整。我重现了这个问题并得到了下一个编译器警告:CS8604 Possible null reference argument for parameter 'item' in 'void List<string>.Add(string item)
。警告出现在下一行
lines.Add(reader.ReadLine());
因为 List<string> lines
是不可为空的 string
值的列表,并且方法 StreamReader.ReadLine()
可以 return 为空 string?
(参见 reference source).因此,在上面的代码行中,这些是尝试将 null
字符串值添加到不可为 null 的字符串列表中。
要解决此问题,您可以使用以下任一方法:
Use null-forgiving operator. 你肯定知道表达式的结果
reader.ReadLine()
不能是null
因为它是在未到达流末尾时执行的。因此,您可以使用 null-forgiving 运算符来抑制警告:lines.Add(reader.ReadLine()!);
检查表达式
reader.ReadLine()
的结果是否为空。如果使用下一个警告将消失的代码:string? line = reader.ReadLine(); if (line != null) lines.Add(line);
更新
正如@IanRingrose 在评论中指出的那样,可以在循环中使用条件 line != null
而不是条件 !reader.EndOfStream()
。使用这样的条件解可以更清楚:
string? line;
while ((line = reader.ReadLine()) != null)
{
lines.Add(line);
}
现在我们不需要在循环体中使用 null-forgiving 运算符或附加条件。
回答您关于 reader 本身的可空性的具体问题:reader
是一个 StreamReader?
,因为 NRT 决定使用 var
将推断变量的类型为 nullable.
nullable implicitly typed local variables
var
infers an annotated type for reference types. For instance, invar s = "";
thevar
is inferred asstring?
.
language design notes 解释这个决定。最终他们得出结论:
Make
var
have a nullable annotated type and infer the flow type as normal.
想法是,由于没有 var?
的语法,该类型被推断为最不严格的类型(即,允许稍后对变量进行 null
赋值)。最终,可空性 应该 通过流分析进行跟踪。
也就是说,已知使用 OpenText
总是 return 一个非 null
对象(否则它会抛出)并且有一个 non-nullable return type。要解决您的问题,只需将您的变量直接声明为 StreamReader
:
StreamReader reader = File.OpenText(path);
正如其他答案所指出的,我认为您对实际错误及其发生位置感到困惑。 “项目”唯一会出现的地方是调用 List<>.Add
时。当然,这是因为 StreamReader.ReadLine
可以 return null
而您的列表声明为 List<string>
而不是 List<string?>
您的选择是:
- 更改列表的类型(可能不会)
- 使用 null-forgiving 运算符
reader.ReadLine()!
(也许,但只有在保证的情况下) - 使用局部变量并在添加到列表之前添加对
null
的检查(直接或通过修改循环条件来执行赋值和空检查)
您可以将所有代码减少到只有两行 Nullable-friendly 行:
string path = "FileName.txt";
var lines = File.ReadLines(path).ToList();