#c# #linq #yield
#c# #linq #yield
Вопрос:
У меня есть следующий метод:
public string GetDepartmentTitle(string DepartmentAbbreviation) {
List<TaxonomyItem> Divisions = TaxonomyFromCMS.GetAllItems(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);
List<TaxonomyItem> Departments = new List<TaxonomyItem>();
Divisions.ForEach(delegate(TaxonomyItem Division) {
Departments.AddRange(Division.SubTaxonomyItems);
});
TaxonomyItem Result = (from d in Departments
where d.Name == DepartmentAbbreviation
select d).FirstOrDefault();
return Result == null ? "" : Result.Title;
}
Сначала он считывает все подразделения (которых всего 3), но у этих подразделений есть много отделов под ними в качестве SubTaxonomyItems. В настоящее время я прохожу по каждому из подразделений, извлекаю каждый из отделов и помещаю их в список под названием Departments. Затем я использую Linq для поиска конкретного элемента.
Это отлично работает, но я бы с удовольствием пропустил / использовал этот первый шаг получения подпунктов. Я попробовал следующую строку, которая, похоже, не работает:
TaxonomyItem Result = (from d in Departments.SubTaxonomyItems
Затем я, возможно, использую какой-нибудь лямбда-код с указанием каждого из отделов.SubTaxonomyItems, который содержит оператор yeild. Возможно, в этом и заключается хитрость, но я не смог заставить ее работать. Глядя на инструкцию yeild, кажется, что может быть способ, если я создам какой-нибудь метод расширения. Но я хочу посмотреть, можно ли это сделать встроенным и похожим на следующий псевдокод:
public string GetDepartmentTitle(string DepartmentAbbreviation) {
List<TaxonomyItem> Divisions = TaxonomyFromCMS.GetAllItems(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);
TaxonomyItem Result = (from d in Divisions.ForEach(delegate(TaxonomyItem Division) {
yeild return Divison.SubTaxonomyItems;
}) AS Dps
where Dps.Name == DepartmentAbbreviation
select Dps).FirstOrDefault();
return Result == null ? "" : Result.Title;
}
Возможно ли это таким образом или каким-то другим способом, которого я не вижу? Можно ли это вообще сделать без метода расширения?
Ответ №1:
Во-первых, вы можете легко решить свою проблему, просто добавив еще одно «from» к запросу:
var query = from division in divisions
from department in division.Departments
where department.Name == whatever
select department;
Это делает именно то, что вы делали; он выбирает последовательность отделов из каждого подразделения и склеивает все эти последовательности вместе, чтобы создать одну длинную последовательность отделов.
Это дает вам простой синтаксис для сценария «сшить вместе кучу последовательностей». В более общем плане, однако, иногда вы сталкиваетесь с подобной ситуацией:
var bars = from foo in foos
some complicated query logic here
select foo.bar;
var abcs = from bar in bars
some other query logic here
select bar.abc;
и вы хотите выяснить, как превратить это в один запрос. Вы можете сделать это следующим образом:
var abcs = from bar in (
from foo in foos
some complicated query logic here
select foo.bar)
some other query logic here
select bar.abc;
что некрасиво, или вы можете сделать это:
var abcs = from foo in foos
some complicated query logic here
select foo.bar into bar
some other query logic here
select bar.abc;
Это делает точно то же самое, но читать его приятнее. Этот синтаксис называется «продолжением запроса».
Чтобы ответить на ваш конкретный вопрос: недопустимо указывать «yield return» в анонимном методе или lambda. Это весьма прискорбно, потому что это было бы действительно полезно. Преобразования, которые выполняет компилятор, чтобы заставить работать анонимные функции и блоки итераторов, довольно сложны, и до сих пор мы всегда пытались заставить их полностью работать вместе. (То есть вы можете поместить лямбда-выражение в блок итератора, но вы не можете поместить блок итератора в лямбда-выражение.) Я надеюсь, но не обещаю, что когда-нибудь мы сможем исправить этот код и разрешить лямбды итератора блокировать. (Помните, размышления Эрика о будущих возможностях языка предназначены только для развлекательных целей.)
Ответ №2:
Похоже, вы просто хотите что-то вроде этого.
public string GetDepartmentTitle(string DepartmentAbbreviation) {
var items = TaxonomyFromCMS.GetAllItems(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);
var result = items.SelectMany(item=>item.SubTaxonomyItems).FirstOrDefault(item=>item.Name == DepartmentAbbreviation);
var text = result !=null ? result.Title : String.Empty;
return text;
}
Комментарии:
1. Черт возьми, ты меня опередил!
Ответ №3:
Возврат Yield может использоваться только в very select (каламбур!) местоположения, и запрос Linq не является одним из них. К счастью, здесь это не нужно.
var q = from division in Divisions
from dps in division.SubTaxonomyItems
where dps.Name == DepartmentAbbreviation
select dps.Title;
return q.FirstOrDefault() ?? String.Empty;
Ответ №4:
Почему бы просто не сделать:
var divisions = TaxonomyFromCMS.GetAllItems
(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);
var titles = from division in divisions
from deparment in division.SubTaxonomyItems
where deparment.Name == DepartmentAbbreviation
select deparment.Title;
return titles.FirstorDefault() ?? "";
Ответ №5:
Это linq, который вы ищете?
var Result = Divisions.SelectMany(d => d.SubTaxonomyItems).Where(subItem => subItem.Name == DepartmentAbbreviation).FirstOrDefault();
Комментарии:
1. Каков тип «подпункта» в вашем коде? Похоже, что это последовательность отделов, но вы рассматриваете это как отдел.
2. Это элемент разделения. Элементы подтаксономии. Возможно, я неправильно понимаю его проблему, пожалуйста, сообщите мне 🙂 Спасибо.
3. Правильно. «Выбрать» возвращает последовательность последовательностей элементов . Вы предполагаете, что Select возвращает последовательность элементов — что он «выравнивает» последовательность последовательностей, — но это не то, что делает Select; это то, что делает SelectMany. В вашем коде каждая последовательность в последовательности будет передана в «Where», поэтому «SubItem» будет последовательностью элементов, а последовательность элементов не имеет имени. У каждого элемента есть Название.
4. Интересно. Я проверил разницу, и вы совершенно правы. Select возвращает группы элементов, в то время как SelectMany выбирает отдельные элементы из условия. Я запомню это. Спасибо.