Запрос C # LINQ для анонимных типов, содержащих динамический список - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть фрагмент кода C #, в котором я создал объект анонимного типа следующим образом:

    var measurementUnits = new List<dynamic>() {
    new { Unit = "SQF", Display = new List<string>() { "F", "FT", "SQ FT" }, Ratio=1.5 } ,
    new { Unit = "Hectares", Display = new List<string>() { "H", "HEC"} , Ratio=2.5},
    new { Unit = "Acres", Display = new List<string>() { "AC(TO)" } , Ratio=3.5},
    new { Unit = "SQM", Display = new List<string>() {  "M", "SQ M"}, Ratio=4.5 }
};

Через LINQ я хочу получить доступ к коэффициенту где Display = "HEC" (без учета регистра) что-то вроде:

var multiplier = measurementUnits.Where(m => m.Display == "HEC").First().Ratio;

Ответы [ 6 ]

0 голосов
/ 01 февраля 2019

Вы можете сделать все это с FirstOrDefault:

 var multiplier = measurementUnits.FirstOrDefault(x => x.Display.Contains("H"))?.Ratio
0 голосов
/ 01 февраля 2019

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

В чем разница между статически типизированными и динамически типизированными языками?

var measurementUnits = new List<dynamic>() {
     new { Unit = "SQF", Display = new List<string>() { "F", "FT", "SQ FT" }, Ratio=1.5  ,
     new { Unit = "Hectares", Display = new List<string>() { "H", "HEC"} , Ratio=2.5 },
     new { Unit = "Acres", Display = new List<string>() { "AC(TO)" } , Ratio=3.5},
     new { Unit = "SQM", Display = new List<string>() { "M", "SQ M"}, Ratio=4.5 } 
};

var multiplier = measurementUnits.Where(m => m.Display.Contains("HEC")).First().Ratio;

Также вам нужно будет проверить множитель для null, так как вы используете First. Это приведет к исключению нулевой ссылки, если значение не найдено, лучшее решение:

var multiplier = measurementUnits.Where(m => m.Display.Contains("HEC")).FirstOrDefault()?.Ratio;
0 голосов
/ 01 февраля 2019

Это решение:

var measurementUnits = new [] {
    new { Unit = "SQF", Display = new List<string>() { "F", "FT", "SQ FT" }, Ratio=1.5 } ,
    new { Unit = "Hectares", Display = new List<string>() { "H", "HEC"} , Ratio=2.5},
    new { Unit = "Acres", Display = new List<string>() { "AC(TO)" } , Ratio=3.5},
    new { Unit = "SQM", Display = new List<string>() {  "M", "SQ M"}, Ratio=4.5 }
};
var multiplier = measurementUnits.Where(m => m.Display.IndexOf("H") > -1).FirstOrDefault()?.Ratio;
0 голосов
/ 01 февраля 2019

Одним из возможных решений является исключение ключевого слова dynamic.Попробуйте этот код

var measurementUnits = new [] {
    new { Unit = "SQF", Display = new List<string>() { "F", "FT", "SQ FT" }, Ratio=1.5 } ,
    new { Unit = "Hectares", Display = new List<string>() { "H", "HEC"} , Ratio=2.5},
    new { Unit = "Acres", Display = new List<string>() { "AC(TO)" } , Ratio=3.5},
    new { Unit = "SQM", Display = new List<string>() {  "M", "SQ M"}, Ratio=4.5 }
};

var multiplier = measurementUnits.Where(m => m.Display.Contains("HEC")).First().Ratio;

Также было бы лучше заменить First на FirstOrDeafult и вручную проверить его на ноль, чтобы избежать исключения NullReference

var unit = measurementUnits.FirstOrDefault(m => m.Display.Contains("HEC"));
if (unit != null)
    var multiplier = unit.Ratio();    
0 голосов
/ 01 февраля 2019

Я полагаю, что вы хотите указать, где в Display "есть" "HEC", поскольку это список.PS: в вашем ОП неясно, хотите ли вы фильтровать по «H» или «HEC» (код и описание не совпадают).Предполагая, что это будет "HEC"

var result = measurementUnits.Where(x=>x.Display.Contains("HEC")).Select(x=>x.Ratio);

или Если вы хотите первый

var result = measurementUnits.Where(x=>x.Display.Contains("HEC")).First().Ratio;
0 голосов
/ 01 февраля 2019

Технически вы можете поместить что-то вроде этого (обратите внимание, что Display - это коллекция, которая может Contain, но не может быть равна одному элементу "H"):

  // 2.5
  var multiplier = measurementUnits
    .First(item => item.Display.Contains("H"))
    .Ratio;

ОднакоДля этого я рекомендую использовать пользовательский класс , а не dynamic, который подвержен ошибкам во время выполнения (что, если Display является string, а не List<string>).

Редактировать: Если существует вероятность, что такого элемента нет (скажем, "HEC2"), и вы не хотите, чтобы исключение было выброшено, но было значением по умолчаниюизменить First на FirstOrDefault:

  // 0.0 - default ratio, since "HEC2" is not found
  var multiplier = measurementUnits
    .FirstOrDefault(item => item.Display.Contains("HEC2"))   
   ?.Ratio ?? 0 /* Default Ratio Value Here */;
...