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