在C#中,我使用StreamReader
来读取文件,每行一行。我还将当前行的编号保留在int
中,以报告可能的错误消息。
读取每一行都会进行一些测试(例如,以#
开头的行是注释,需要跳过),所以我打算将整个阅读过程放在一个函数中,这将保持不变阅读直到遇到有用的行,然后返回该行。如果遇到EOF
,则会返回null
。
当我将此函数定义为string read(StreamReader sr, out int lineNumber)
时,我认为我很聪明,但现在事实证明C#将无法在该函数内执行lineNumber++
之类的操作。它假定该变量尚未分配,可能是因为它无法知道它是否已在此函数调用之前分配。
所以,问题很简单:如何指定此变量是inout
参数(我认为这是一个术语;我听说它是在其他编程语言的上下文中提到的)?这首先是可能的吗? 我绝对不会让lineNumber
成为我班级的成员,所以这不是一个选项。
答案 0 :(得分:17)
在这种情况下,您需要ref
参数而不是out
。使用out
关键字,分配/实例化值的责任在于调用调用方法;使用ref
它位于被调用方法之外。
答案 1 :(得分:1)
使用ref关键字而不是out。这将强制调用者在调用之前初始化参数。
必须首先初始化传递给ref参数的参数。 将此与out参数进行比较,其参数不必是 在传递给out参数之前显式初始化。
答案 2 :(得分:1)
你需要的是
MSDN
方法参数上的ref方法参数关键字会导致方法 引用传递给方法的相同变量。任何 对方法中的参数所做的更改将反映在该方法中 当控制传递回调用方法时变量。
答案 3 :(得分:1)
正如大家所说,你可以简单地使用ref
。
我将建议另一种方法,只是让你意识到这一点。
您可以编写一个返回IEnumerable<Line>
的方法,其中Line
是一个非常简单的类,只包含一行文本和一个行号:
public class Line
{
public string Text;
public int Number;
}
然后你读取线条的方法看起来像这样:
public IEnumerable<Line> ReadLines(StreamReader sr)
{
int number = 0;
while (true)
{
string line = sr.ReadLine();
if (line == null)
break;
++number;
if (wantLine(line)) // Some predicate which decides if you want to keep the line.
yield return new Line{Text = line, Number = number};
}
}
然后您可以按如下方式使用它:
public void Test()
{
StreamReader sr = new StreamReader("Whatever");
foreach (var line in ReadLines(sr))
{
if (line.Text == "SomeSpecialValue")
doSomethingWith(line.Text, line.Number);
}
}
这是更多的工作要写,但我认为它可以产生更清晰的代码,并且它还具有线号计数器完全隐藏在ReadLines()
内的优势。 (它不是你班级的成员,因为它是你班级中的一个领域;它只是方法中的一个局部变量。)