Есть какие-нибудь планы относительно оператора LINQ “do” / Action?
Вопрос
Вот простой метод с foreach
петля:
IEnumerable<XElement> FieldsToXElements(object instance)
{
var fieldElements = new List<XElement>();
foreach (var field in instance.GetType().GetFields(instance))
{
fieldElements.Add(new XElement(field.Name, field.GetValue(instance)));
}
return fieldElements;
}
Немного уродливый.Если бы в LINQ был какой-то оператор, который означал бы "сделать что-то" (напримервыполните Action
для каждого выбранного в операторе LINQ), это выглядело бы приятнее, лаконичнее:
IEnumerable<XElement> FieldsToXElements(object instance)
{
var fieldElements = new List<XElement>();
from field in instance.GetType().GetFields(instance))
let name = field.Name
let value = field.GetValue(instance)
do fieldElements.Add(new XElement(name, value));
return fieldElements;
}
Я понимаю, что это субъективно и всего лишь мое мнение.Для цикла foreach, который имеет одну строку, которая просто вызывает метод, a "do
"оператор имеет смысл, на мой взгляд. Но мне интересно, подумал ли кто-нибудь в MS о том же самом.Планируется ли такой оператор LINQ в каких-либо предстоящих выпусках (напримернаряду с дебютом C # 4.0)?
Вот еще один пример с предикатом, где фиктивное do
operator действительно сделал бы код более чистым.Это:
IEnumerable<XElement> FieldsToXElements
(object instance, Func<FieldInfo, bool> predicate)
{
var fieldElements = new List<XElement>();
foreach (var field in instance.GetType().GetFields(instance).Where(predicate))
{
fieldElements.Add(new XElement(field.Name, field.GetValue(instance)));
}
return fieldElements;
}
против.это:
IEnumerable<XElement> FieldsToXElements
(object instance, Func<FieldInfo, bool> predicate)
{
var fieldElements = new List<XElement>();
from field in instance.GetType().GetFields(instance))
let name = field.Name
let value = field.GetValue(instance)
where predicate(field)
do fieldElements.Add(new XElement(name, value));
return fieldElements;
}
Решение
Нет, я не ожидаю никакого прямого язык suport (i.e.внутри синтаксиса запроса) в ближайшее время.
Это звучит так, как будто ты имеешь в виду мифическое ForEach
способ расширения;добавить тривиально, но Эрик Липперт много раз комментировал нечто среднее между функциональным кодом без побочных эффектов и Action<T>
с побочными эффектами.В частности, деревья выражений C # 3.0 / .NET 3.5 плохо справляются с побочными эффектами (что затрудняет полную поддержку lambda).Сторона выполнения намного лучше в .NET 4.0, но на данный момент неясно, какая часть этого войдет в язык (лямбда-компилятор) в C # 4.0.
Все, что вам нужно (для версии делегата), это:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{ // note: omitted arg/null checks
foreach(T item in source) { action(item); }
}
Затем из любого запроса вы можете просто использовать .ForEach(x => /* do something */)
.
Другие советы
Для вашего конкретного примера (заполнение List<XElement>
), я бы сделал это таким образом.
IEnumerable<XElement> FieldsToXElements(object instance)
{
List<XElement> fieldElements =
(
from field in instance.GetType().GetFields(instance))
let name = field.Name
let value = field.GetValue(instance)
select new XElement(name, value)
).ToList(); //Another Option is List<T>.AddRange()
return fieldElements;
}
Также:Не забывай об этом List<T>
уже реализует .ForEach<T>()
, поэтому использовать его против любого Enumerable<T>
, это весь код, который вам нужен.
myEnumerable.ToList().ForEach( x => myAction(x) );
Я не думаю, что это слишком сложно, или, может быть, я что-то упускаю...
IEnumerable<XElement> FieldsToXElements(object instance)
{
return instance.GetType()
.GetFields(instance)
.Select( f => new XElement( f.Name,
f.GetValue(instance) ) );
}
Если вы просто смотрите на вызов функции из вашего оператора linq, то вы уже можете это сделать, вы можете вызвать функцию в присваивании Let .
var qry = from e in somelist
let errorcode = DoSomeProcessing(e)
select e;