Любые планы для оператора "do" /Action LINQ?
Вот простой метод с циклом 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, который имеет одну строку, которая просто вызывает метод, оператор "do
" имеет смысл, на мой взгляд. Но мне интересно, думал ли кто-нибудь в MS о том же. Является ли такой оператор LINQ запланированным в любых будущих выпусках (например, вместе с дебютом С# 4.0)?
Вот еще один пример с предикатом, где фиктивный оператор do
действительно сделает код более чистым. Это:
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;
}
Ответы
Ответ 1
Нет, я не ожидаю, что какой-либо прямой язык suport (т.е. внутри синтаксиса запроса) в ближайшее время.
Похоже, вы имеете в виду мифический метод расширения ForEach
; тривиально добавить, но Эрик Липперт много раз прокомментировал перекресток функционального кода без побочных эффектов и Action<T>
с побочными эффектами. В частности, деревья выражений С# 3.0/.NET 3.5 паршивы в side-effecs (что делает полную поддержку лямбда сложным). Сторона времени выполнения намного лучше в .NET 4.0, но пока неясно, сколько из этого выйдет на язык (компилятор lambda ) в С# 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 */)
.
Ответ 2
В вашем конкретном примере (заполнение 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) );
Ответ 3
Я не думаю, что это слишком сложно или, может быть, я что-то пропустил...
IEnumerable<XElement> FieldsToXElements(object instance)
{
return instance.GetType()
.GetFields(instance)
.Select( f => new XElement( f.Name,
f.GetValue(instance) ) );
}
Ответ 4
Если вы просто смотрите на вызов функции из своей инструкции linq, вы можете уже сделать это, вы можете сделать вызов функции в назначении Let.
var qry = from e in somelist
let errorcode = DoSomeProcessing(e)
select e;