Поддерживает ли C# входные параметры?
В C# я использую StreamReader
читать файл, строка за строкой. Я также держу номер текущей строки в int
, для сообщений о возможных сообщениях об ошибках.
Чтение каждой строки сопровождается некоторыми тестами (например, строки, начинающиеся с #
комментарии, и их нужно пропустить), поэтому я планирую поместить всю процедуру чтения в функцию, которая будет продолжать чтение до тех пор, пока не встретит полезную строку, а затем вернет эту строку. Если это сталкивается EOF
это просто вернется null
,
Я думал, что был умным, когда я определил эту функцию как string read(StreamReader sr, out int lineNumber)
, но теперь получается, что C# не сможет сделать что-то вроде lineNumber++
внутри этой функции. Предполагается, что переменная еще не была назначена, возможно потому, что у нее нет способа узнать, была ли она назначена до вызова этой функции.
Итак, проблема проста: как я могу указать, что эта переменная inout
параметр (я думаю, что это термин; я слышал, что он упоминается в контексте других языков программирования)? Это вообще возможно в первую очередь? Я абсолютно не собираюсь делать lineNumber
член моего класса, так что это не вариант.
4 ответа
В этом случае вам нужно ref
параметр вместо out
, С out
ключевое слово, ответственность за назначение / создание значения лежит в вызывающем вызываемом методе; с ref
он лежит вне вызываемого метода.
Также смотрите: Когда использовать ref vs out
Реф это то что тебе нужно
MSDN
Ключевое слово параметра метода ref в параметре метода заставляет метод ссылаться на ту же переменную, которая была передана в метод. Любые изменения, внесенные в параметр в методе, будут отражены в этой переменной, когда управление вернется к вызывающему методу.
Используйте ключевое слово ref вместо out. Это заставит звонящего инициализировать аргумент перед вызовом.
Аргумент, передаваемый параметру ref, должен сначала быть инициализирован. Сравните это с параметром out, чей аргумент не нужно явно инициализировать перед передачей в параметр out.
Как все говорят, вы можете просто использовать 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()
, (Это не член вашего класса в том смысле, что это поле в вашем классе; это просто локальная переменная в методе.)