17

在 C# 中,我使用 aStreamReader读取文件,每行一行。我还将当前行的编号保留在 中int,以报告可能的错误消息。

阅读每一行都伴随着一些测试(例如,以#注释开头的行,需要跳过),所以我打算将整个阅读过程放在一个函数中,它会一直阅读,直到遇到有用的行,然后返回该行。如果遇到EOF它将简单地返回null

当我将此函数定义为 时,我以为我很聪明string read(StreamReader sr, out int lineNumber),但现在事实证明,C# 将无法lineNumber++在该函数内部执行类似的操作。它假设变量还没有被赋值,可能是因为在这个函数调用之前它没有办法知道它是否已经被赋值。

所以,问题很简单:我怎样才能指定这个变量是一个inout参数(我认为这是一个术语;我听说它在其他编程语言的上下文中被提及)?这甚至可能吗?我绝对不会成为lineNumber我班的一员,所以这不是一个选择。

4

4 回答 4

18

在这种情况下,您需要一个ref参数而不是out. 使用out关键字,分配/实例化值的责任在于调用被调用的方法;它位于被调用的ref方法之外。

另请参阅:何时使用 ref 与 out

于 2013-05-02T08:00:58.493 回答
1

正如大家所说,您可以简单地使用ref.

我将建议一种替代方法,以便您了解它。

您可以编写一个返回IEnumerable<Line>where的方法,这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()。(它不是类的成员,因为它是类中的一个字段;它只是方法中的一个局部变量。)

于 2013-05-02T08:13:53.620 回答
1

使用 ref 关键字而不是 out。这将强制调用者在调用之前初始化参数。

来自MSDN - ref (C#)

必须首先初始化传递给 ref 参数的参数。将此与 out 参数进行比较,其参数在传递给 out 参数之前不必显式初始化。

于 2013-05-02T08:02:20.660 回答
1

一个 ref 是你需要的

MSDN

方法参数上的 ref 方法参数关键字导致方法引用传递给该方法的相同变量。当控制权传递回调用方法时,对方法中的参数所做的任何更改都将反映在该变量中。

于 2013-05-02T08:02:29.517 回答