Следующее поколение Visual C ++, которое должно выйти целых две недели, включает в себя std::thread
библиотеки, а G ++ уже, если я не ошибаюсь. Я бы не посчитал это против этого. И вот в чем дело: C ++ 11 действительно очень важен. Если ваше рабочее место не планирует мигрировать, я найду другое рабочее место.
Я не вижу необходимости в этом методе. Просто используйте Where ().
var sublist = list.Where( expression.Compile() ).ToList();
Или, что еще лучше, определите выражение как встроенное лямбда-выражение. почему "урожайность" не допускается внутри анонимный метод или лямбда-выражение
A:
Хороший вопрос. Я бы хотел иметь анонимные блоки итератора. Это было бы совершенно потрясающе иметь возможность строить себе небольшой генератор последовательности на месте, которые закрыли местные переменные. Причина, почему нет просто: преимущества не перевешивают затраты. Великолепие создание генераторов последовательностей на месте - это на самом деле довольно маленький в большом схема вещей и именные приемы делать работу достаточно хорошо в большинстве сценарии. Так что пользы нет
Затраты велики. Итератор переписывание - самое сложное преобразование в компиляторе, и переписывание анонимного метода - это второй по сложности. Анонимный методы могут быть внутри других анонимных методы, а анонимные методы могут быть внутри блоков итератора. Следовательно, то, что мы делаем, сначала мы переписываем все анонимные методы, чтобы они стали методы класса закрытия. Это второе и последнее, что компилятор выполняет перед отправкой IL для метода. Как только этот шаг будет выполнен, итератор переписчик может предположить, что нет анонимные методы в итераторе блок; они все были переписаны уже. Следовательно, итератор переписчик может просто сосредоточиться на переписывая итератор, без беспокоясь, что может быть там нереализованный анонимный метод.
Кроме того, блоки итератора никогда не "вкладываются", в отличие от анонимных методов. Итератор rewriter может предполагать, что все итераторы блоки являются «верхним уровнем».
Если анонимные методы разрешены содержат блоки итератора, тогда оба эти предположения выпадают из окна. У вас может быть блок итератора, который содержит анонимный метод, который содержит анонимный метод, который содержит блок итератора, который содержит анонимный метод и ... фу. Теперь надо написать переписывание проход, который может обрабатывать вложенный итератор блоки и вложенные анонимные методы в в то же время, объединяя два наших самых сложные алгоритмы в один далеко более сложный алгоритм. Было бы быть очень сложным в разработке, реализации, и тест. Мы достаточно умны, чтобы делать так что я уверен. У нас есть умная команда Вот. Но мы не хотим брать на себя это большое бремя для "приятно иметь но не обязательная »функция. - Эрик
Эрик Липперт написал отличную серию статей об ограничениях (и проектных решениях, влияющих на этот выбор) для блоков итераторов
В частности, блоки итераторов реализованы некоторым сложным кодом компилятора. трансформации. Эти преобразования будут влиять на преобразования, которые происходят внутри анонимных функций или лямбда-выражений, так что в определенных обстоятельствах они оба будут пытаться «преобразовать» код в какую-то другую конструкцию, несовместимую с другой.
В результате им запрещено взаимодействия.
Как блоки итератора работают под капотом, хорошо здесь .
В качестве простого примера несовместимости:
public IList<T> GreaterThan<T>(T t)
{
IList<T> list = GetList<T>();
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item; // This is not allowed by C#
}
return items.ToList();
}
Компилятор одновременно хочет преобразовать это во что-то вроде:
// inner class
private class Magic
{
private T t;
private IList<T> list;
private Magic(List<T> list, T t) { this.list = list; this.t = t;}
public IEnumerable<T> DoIt()
{
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item;
}
}
}
public IList<T> GreaterThan<T>(T t)
{
var magic = new Magic(GetList<T>(), t)
var items = magic.DoIt();
return items.ToList();
}
и в то же время аспект итератора пытается сделать свою работу по созданию небольшого конечного автомата. Некоторые простые примеры могут работать с достаточным количеством проверок работоспособности (сначала имея дело с (возможно, произвольными) вложенными замыканиями), а затем проверять, могут ли результирующие классы самого нижнего уровня быть преобразованы в конечные автоматы итератора.
Однако это будет
В вашем примере так:
public IList<T> Find<T>(Expression<Func<T, bool>> expression)
where T : class, new()
{
return FindInner(expression).ToList();
}
private IEnumerable<T> FindInner<T>(Expression<Func<T, bool>> expression)
where T : class, new()
{
IList<T> list = GetList<T>();
var fun = expression.Compile();
foreach (var item in list)
if (fun.Invoke(item))
yield return item;
}
К сожалению, я не знаю почему они не позволили этого, поскольку, конечно, вполне возможно представить себе, как это будет работать.
Однако анонимные методы уже являются частью «магии компилятора» в том смысле, что метод будет извлечен либо в в существующем классе или даже в совершенно новом классе, в зависимости от того, имеет ли он дело с локальными переменными или нет.
Кроме того, методы итератора, использующие yield
, также реализованы с использованием магии компилятора.
Я предполагаю, что один из этих двух делает код неидентифицируемым для другого волшебства, и было решено не тратить время на выполнение этой работы для текущих версий компилятора C #.Конечно, это может быть вовсе не осознанный выбор, и что он просто не работает, потому что никто не подумал его реализовать.
Для 100% точного вопроса я предлагаю вам использовать Microsoft Connect ] и задайте вопрос, я уверен, что взамен вы получите что-нибудь полезное.
Я бы сделал следующее:
IList<T> list = GetList<T>();
var fun = expression.Compile();
return list.Where(item => fun.Invoke(item)).ToList();
Конечно, вам понадобится System.Core.dll, на который имеется ссылка в .NET 3.5 для метода Linq. И включают:
using System.Linq;
Ура,
Хитрый