2013-03-07 4 views
4

Я пытаюсь прочитать в файле, который по существу представляет собой список целых чисел, разделенных линией. Очевидно, что вход в файл никогда нельзя доверять, поэтому мне нужно отфильтровать нецелые числа.Простой способ чтения целых чисел из файла

Я знаю, что оператор as обычно преобразует, если он может, а затем присваивает нуль, однако из-за int не NULLABLE это ISN Это дело. Я подумал, что, может быть, я могу бросить на Nullable<int>. Я действительно никогда не вникал в это, я думал, возможно, я мог бы сделать:

var lines = File.ReadAllLines(""); 
var numbers = lines.Select(line => line as int?).Where(i => i != null); 

Я знаю, что я мог бы получить потенциально обойти эту проблему, выполнив:

var numbers = lines.Select(line => 
            { 
            int iReturn = 0; 
            if (int.TryParse(line, out iReturn)) 
             return iReturn; 
            else 
             return null;   
            }).Where(i => i != null); 

Я также потенциально мог бы сделать это как способ расширения.

Я просто искал аккуратный, лаконичный способ сделать актерский состав в заявлении, а также понять, почему мой код недействителен.

+0

Nope. C# намеренно осторожно относится к подобным вещам. –

+0

@ColonelPanic это, вероятно, есть, но почему, если я обрабатываю тот факт, что он потенциально может быть нулевым, это не вслух? В чем разница между этим и отбрасыванием 'Foo object'' как '' Bar object'? – LukeHennerley

+0

Кроме того, если защита защищена от вредоносного ввода, вызов File.ReadAllLines (...) должен быть заменен перечислителем (или эквивалентной функциональностью), который считывает строки и проверяет их последовательно и ограничивает их длину. –

ответ

3

Я всегда использовать этот простой метод расширения:

public static int? TryGetInt(this string item) 
{ 
    int i; 
    bool success = int.TryParse(item, out i); 
    return success ? (int?)i : (int?)null; 
} 

Тогда это легко:

var numbers = lines.Select(line => line.TryGetInt()) 
        .Where(i => i.HasValue) 
        .Select(i => i.Value); 

Вы также можете использовать int.TryParse без расширения, но это не документировано, следовательно, может прекратить работу в будущее:

int i = 0; 
var numbers = lines.Where(line => int.TryParse(line, out i)) 
        .Select(line => i); 

Редактировать

"также понять, почему мой код неверен"

соответствующий код:

if (int.TryParse(line, out iReturn)) 
    return iReturn; 
else 
    return null; 

Это будет работать, если вы хотите заменить

else 
    return null; 

с

else 
    return (int?)null; 

потому что вы возвращаете int, но null неконвертируется неявно на int.

0

Nope. C# намеренно осторожно относится к изменению строк в числах.

Вы можете сделать ваш код короче (не более аннулирует) с использованием цикла Еогеасп

var numbers = new List<int>(); 

foreach(string line in lines) 
{ 
    int n; 
    if (int.TryParse(line, out n)) 
     numbers.Add(n); 
} 
1

Существует не короткий путь, чтобы сделать это, потому что здесь не нужно отбрасывать (вы не можете cast) - вам нужно конвертировать из одного типа в другой. Типы курсов: int и string (так что не совсем «любые»), но, как и в общем случае, любое преобразование между несвязанными типами невозможно сделать «точно так же».

+0

@LukeHennerley: Ваша терминология неверна, поэтому вам следует дважды проверить свои факты. 'foo as Bar' не бокс; бокс - это то, что происходит, когда вы ставите типы значений в «объект». 'string' не может быть * принудительным * для любого типа - что означает« принудительный »? – Jon

+0

@ LukeHennerley: В целом, приведения, которые не меняют/unbox, не меняют * ничего * во время выполнения. То, что они меняют, - это информация о бухгалтерии, которую компилятор имеет во время компиляции. – Jon

+0

Извините, ха-ха, не использовал эту терминологию с тех пор, как тренировался: P Но спасибо, что прояснил это для меня, +1. – LukeHennerley

0

Вы можете создать и метод расширения

public static int? ToInt(this string s, int default){ ... } 

и использовать его в LINQ:

var lines = File.ReadAllLines(path); 
var numbers = lines.Select(line => line.ToInt()) 
        .Where(i => i != null); 
0

Если я вас правильно понимаю, и вы хотите просто фильтровать НЕРАСПРОСТРАНЕНИИ целые строки, возможно регулярное выражение вариант ?

var lines = File.ReadAllLines(""); 
var numbers = lines.Where(i => Regex.IsMatch(i, "[0-9]+")); 
+0

Я хочу, чтобы фильтр да, но я хочу вернуть 'int []', очевидно, что 'var' не является явным признаком этого - извините. – LukeHennerley

+0

Вопрос связан с кастингом, хотя, хотя это может быть предварительным фильтром, каким будет ответ на фактический вопрос? – LukeHennerley

0

Вот лучшее, что я придумал:

Используйте этот метод расширения:

public static class Int32Extensions 
    { 
     public static int? ParseOrDefault(this string text) 
     { 
      int iReturn = 0; 
      if (int.TryParse(text, out iReturn)) 
      { 
       return iReturn; 
      } 
      return null; 
     } 
    } 

Как это:

var query = lines.Select(x => x.ParseOrDefault()).Where(x => x.HasValue);