2013-03-04 7 views
1

позволяет сказать, что у меня есть строка ввода, которую мне нужно форматировать в список из KeyValuePair<string,float> записей. Формат входной строки являетсяВыбрасывание исключений из исключения Linq Query

key:value;key:value;... 

позволяет сказать, что у меня есть это Linq код, чтобы сделать это

var orr = from pco in (overrrides ?? string.Empty).Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 
      let pair = pco.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries) 
      select new KeyValuePair<string, float>(pair[0], float.Parse(pair[1])); 

Теперь, если входная строка не правильно отформатированный LINQ потерпит неудачу на двух возможных точек, индекс вне диапазона на pair[] и исключение формата по float.Parse. Оба этих исключения будут подпрыгивать и ничего не означают для вызывающего.

Я знаю, что у меня есть два метода обхода (не используйте linq и loop как его 1990-е годы или не хватайте выше исключений и переупаковки), однако мне было интересно, могу ли я каким-то образом ввести шаги проверки в сам запрос linq, чтобы выбросить мои собственные исключения, если я обнаруживаю аномалия (pair.length<2 или pair[1] не число)?

+0

pair.length не будет никакой проблемой - вы можете использовать предложение where. Для float.Parse вы можете попробовать некоторую конструкцию с помощью TryParse, но в этом случае вы должны рассмотреть возможность разбить linq на элементы linq + foreach для удобства чтения;) – TGlatzer

+0

@ J.Steen, правильно, извините, исправлено. – mmix

+0

Не беспокойтесь, просто не хотелось бы, чтобы люди фокусировались на опечатках. =) (как и я!);) –

ответ

1

Я предполагаю, что я думал, что делать нельзя, так как throw, так как заявление, не может быть использовано в лямбда-выражения. Единственный способ - создать внешнюю функцию с побочным эффектом и запустить ее через оператор let или where, который будет применять его к каждой записи.

var pairIsValidOrDie = new Func<string[], bool>(pair => { 
    float amt; 
    if (pair.Length != 2 || !float.TryParse(pair[1], out amt)) throw new ArgumentException("ERROR: invalid price override string); 
    return true; 
}); 

var orr = from pco in (overrrides ?? string.Empty).Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 
      let pair = pco.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries) 
      where pairIsValidOrDie(pair) 
      select new KeyValuePair<string, float>(pair[0], float.Parse(pair[1])); 
3

Один простой вариант, чтобы изменить его:

// I don't think I'd use ?? like this, but that's not the point of the question. 
var unparsed = (overrrides ?? string.Empty).Split(new char[] { ';' }, 
                StringSplitOptions.RemoveEmptyEntries); 
var parsed = unparsed.Select(x => ParsePair(x)); 

... 

static KeyValuePair<string, float> ParsePair(string text) 
{ 
    // Note that you could be more efficient using IndexOf/Substring 
    string[] bits = text.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); 
    if (bits.Length != 2) 
    { 
     throw new ArgumentException("Value should be a colon-separated key/float pair"); 
    } 
    float value; 
    if (!float.TryParse(bits[1], out value)) 
    { 
     throw new ArgumentException("Cannot parse " + bits[1] + " as a float"); 
    } 
    return new KeyValuePair<string, float>(bits[0], value); 
} 

Вы все еще используете LINQ для «последовательности» части - вы просто разорвать «как обрабатывать одно значение» часть в отдельный способ. (Вы могли бы сделать это как большой оператор лямбда, но я бы не стал.) Заметим, что таким образом вы можете самостоятельно протестировать метод ParsePair.

(Вы могли бы сойти с рук только .Select(ParsePair), в зависимости от версии C# вы используете. Преобразования группы Способ и вывода типа не являются лучшими друзьями, хотя.)

+0

ОК, это работает и на самом деле просто полезная загрузка пользовательского цикла foreach. Я действительно искал способ встроить исключение в язык запросов. Не только для этой проблемы, но и для будущей справки. – mmix

0

Вы можете проверить строку первой с регулярным выражением

Regex r = new Regex(@"^((\w:\d);)*$"); 
bool test = r.IsMatch(tosplit); 
Смежные вопросы