Затраты на создание исключений, вероятно, превосходят затраты на синтаксический анализ XML. Вам нужно переписать свой код, чтобы он не генерировал исключения.
Один из способов - проверить наличие элемента, прежде чем запрашивать его значение. Это будет работать, но кода много. Другой способ сделать это - использовать карту:
Dictionary<string, string> map = new Dictionary<string, string>
{
{ "matchtype", null },
{ "matches", null },
{ "ballsbowled", null }
};
foreach (XmlElement elm in stats.SelectNodes("*"))
{
if (map.ContainsKey(elm.Name))
{
map[elm.Name] = elm.InnerText;
}
}
Этот код будет обрабатывать все элементы, имена которых вам нужны, и игнорировать те, которые вам не нужны. Если значение на карте равно нулю, это означает, что элемент с таким именем не существовал (или не имел текста).
На самом деле, если вы помещаете данные в DataTable
, а имена столбцов в DataTable
совпадают с именами элементов в XML, вам даже не нужно создавать карту, поскольку свойство DataTable.Columns
- это вся карта, которая вам нужна. Кроме того, поскольку DataColumn
знает, какой тип данных он содержит, вам не нужно дублировать эти знания в своем коде:
foreach (XmlElement elm in stats.SelectNodes("*"))
{
if (myTable.Columns.Contains(elm.Name))
{
DataColumn c = myTable.Columns[elm.Name];
if (c.DataType == typeof(string))
{
myRow[elm.Name] = elm.InnerText;
continue;
}
if (c.DataType == typeof(double))
{
myRow[elm.Name] = Convert.ToDouble(elm.InnerText);
continue;
}
throw new InvalidOperationException("I didn't implement conversion logic for " + c.DataType.ToString() + ".");
}
}
Обратите внимание, что я не объявляю переменные для хранения этой информации, поэтому у меня нет шансов испортить и объявить переменную типа данных, отличного от столбца, в котором она хранится, или создать столбец в моей таблице забыв реализовать логику, которая его наполняет.
Редактировать
Хорошо, вот что-то немного хитрое. Это довольно распространенная техника в Python; в C # я думаю, что большинство людей все еще думают, что в этом есть что-то странное.
Если вы посмотрите на второй пример, который я привел, вы увидите, что он использует метаинформацию в DataColumn
, чтобы выяснить, какую логику использовать для преобразования значения элемента из текста в его базовый тип. Вы можете сделать то же самое, создав свою собственную карту, например ::1010
Dictionary<string, Type> typeMap = new Dictionary<string, Type>
{
{ "matchtype", typeof(string) },
{ "matches", typeof(int) },
{ "ballsbowled", typeof(int) }
}
и затем сделайте то же самое, что я показал во втором примере:
if (typeMap[elm.Name] == typeof(int))
{
result[elm.Name] = Convert.ToInt32(elm.Text);
continue;
}
Ваши результаты больше не могут быть Dictionary<string, string>
, так как теперь они могут содержать вещи, которые не являются строками; они должны быть Dictionary<string, object>
.
Но эта логика кажется немного неуклюжей; Вы тестируете каждый элемент несколько раз, есть continue
операторов, которые можно вырвать - это не страшно, но может быть более кратким. Как? Используя другую карту, отображающую типы в функции преобразования:
Dictionary<Type, Func<string, object>> conversionMap =
new Dictionary<Type, Func<string, object>>
{
{ typeof(string), (x => x) },
{ typeof(int), (x => Convert.ToInt32(x)) },
{ typeof(double), (x => Convert.ToDouble(x)) },
{ typeof(DateTime), (x => Convert.ToDateTime(x) }
};
Это немного сложно читать, если вы не привыкли к лямбда-выражениям. Тип Func<string, object>
определяет функцию, которая принимает string
в качестве аргумента и возвращает объект. И это то, что значения на этой карте: это лямбда-выражения, то есть функции. Они принимают строковый аргумент (x
) и возвращают объект. (Откуда мы знаем, что x
является строкой? Func<string, object>
говорит нам.)
Это означает, что преобразование элемента может занять одну строку кода:
result[elm.Name] = conversionMap[typeMap[elm.Name]](elm.Text);
Переход от внутреннего к внешнему выражению: он ищет тип элемента в typeMap
, а затем ищет функцию преобразования в conversionMap
и вызывает эту функцию, передавая elm.Text
в качестве аргумента.
Это может быть не идеальный подход в вашем случае. Я действительно не знаю. Я показываю это здесь, потому что есть большая проблема в игре. Как отмечает Стив Макконнелл в Code Complete , отладку данных легче, чем отладку кода. Этот метод позволяет вам превратить логику программы в данные. Есть случаи, когда использование этой техники значительно упрощает структуру вашей программы. Это стоит понять.