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

Пример: «1256,553,674» или «346».

Мне нужно сделать пару вещей:

  • Преобразуйте эту строку в int []
  • Выполните «Содержит» для коллекции IEnumerable.
  • Верните эту коллекцию и назначьте ее свойству.

Этот код вызывается внутри .Select при создании нового объекта, а "Vendor" - это свойство этого нового объекта.

Вот мой код, который я использую сейчас:

Vendors = (m.VendorList.Contains(","))
              ? (from v in vendors
                 where m.VendorList.Split(',')
                                   .Select(n => Convert.ToInt32(n))
                                   .ToArray()
                                   .Contains(v.VendorID)
                 select v).ToList()
              : (string.IsNullOrEmpty(m.VendorList))
                    ? null
                    : (from s in vendors
                       where s.VendorID == int.Parse(m.VendorList)
                       select s).ToList()

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

Я как бы новичок в linq, не могли бы вы дать какие-нибудь советы по наведению порядка в этом беспорядке?

Как видите, я использую два тернарных оператора. Первый - определить, является ли это списком, разделенным запятыми. Второй - определить, есть ли в списке, разделенном запятыми, даже значения.

2
MrMango 20 Май 2014 в 07:57

5 ответов

Лучший ответ

Это тот случай, когда я предлагаю вытащить часть этого из вашего оператора LINQ:

var vendorIds = m.VendorList
    .Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries)
    .Select(n => Convert.ToInt32(n))
    .ToArray();

someObj.Vendors = vendors.Where(v => vendorIds.Contains(v.VendorID));
  1. Это более читабельно. Присваивая переменную vendorIds, вы указываете будущим программистам, что означает эта переменная. Им не нужно полностью разбирать весь ваш код LINQ, прежде чем они смогут понять общую цель.
  2. Так будет лучше. В исходном коде вы повторно анализируете весь список поставщиков дважды для каждого значения в vendors. Этот код анализирует его один раз и повторно использует структуру данных для всех ваших проверок идентификаторов. (Если у вас есть большие списки идентификаторов поставщиков, вы можете еще больше повысить производительность, сделав vendorIds HashSet<>.)

Если ваш ввод - пустая строка, часть RemoveEmptyEntries гарантирует, что вы получите пустой список идентификаторов поставщиков и, следовательно, отсутствие соответствующих поставщиков. Если ваш ввод содержит только одно значение без запятых, вы получите единственный идентификатор в списке.

Обратите внимание, что это не будет вести себя точно так же, как ваш исходный код, в том смысле, что он не установит значение null, если задано нулевое или пустое значение m.VendorList. Я предполагаю, что если вы потратите время на то, чтобы подумать об этом, наличие нулевого m.VendorList на самом деле не то, чего вы ожидаете, и было бы лучше "быстро потерпеть неудачу", если это когда-либо случится, чем Остается недоумевать, почему ваша собственность .Vendors оказалась null. Я также предполагаю, что если у вас есть свойство empty .Vendors, потребителям кода будет легче работать правильно, чем если им придется проверять значения null.

0
StriplingWarrior 20 Май 2014 в 05:12

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

Вы могли бы сделать следующее в одной строке кода, но я думаю, что таким образом он будет более читабельным (обслуживаемым).

var Vendors = new List<int>();

if (m.VendorList != null)
    Vendors.AddRange(vendors.Where(v => m.VendorList
                                         .Split(',')
                                         .Select(y => Convert.ToInt32(y))
                                         .Contains(v))
                            .Select(v => v));
2
Grant Winney 20 Май 2014 в 04:24
Vendors = from v in vendors
          let vendorList = from idString in m.Split(',')
                           select int.Parse(idString)
          where vendorList.Contains(v.VendorID)
          select v;

Нет необходимости проверять наличие ",".

1
Aron 20 Май 2014 в 04:18

Вы можете попробовать это:

string str = "356"; //"1256,553,674";

string[] arr = str.Split(',');

List<int> lst = new List<int>();

foreach (string s in arr)
{
    lst.Add(Convert.ToInt32(s));
}

Список будет содержать все числа в вашей строке

0
Gleb 20 Май 2014 в 04:14
string str = "1256,553,674";

IEnumerable<int> array = str.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
0
Aditya Singh 20 Май 2014 в 04:15