Есть ли планы на "сделать" / Action LINQ оператора? - PullRequest
12 голосов
/ 25 января 2009

Вот простой метод с циклом 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 в следующих выпусках (например, вместе с дебютом C # 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;
}

Ответы [ 4 ]

16 голосов
/ 25 января 2009

Нет, я не ожидаю какого-либо прямого языка поддержки (т.е. внутри синтаксиса запроса) в ближайшее время.

Похоже, вы имеете в виду мифический ForEach метод расширения; тривиально добавить, но Эрик Липперт много раз комментировал разницу между функциональным кодом без побочных эффектов и Action<T> с побочными эффектами. В частности, деревья выражений в C # 3.0 / .NET 3.5 неэффективны (что делает полную поддержку лямбды сложной). Сторона выполнения намного лучше в .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 */).

3 голосов
/ 25 января 2009

Для вашего конкретного примера (заполнение 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) );
2 голосов
/ 25 января 2009

Не думаю, что это слишком сложно, или, может быть, я что-то упустил ...

IEnumerable<XElement> FieldsToXElements(object instance)
{
    return instance.GetType()
                   .GetFields(instance)
                   .Select( f => new XElement( f.Name,
                                               f.GetValue(instance) ) );
}
1 голос
/ 25 января 2009

Если вы просто смотрите на вызов функции из вашего оператора linq, то вы уже можете это сделать, вы можете вызвать функцию в назначении Let.

var qry = from e in somelist
          let errorcode = DoSomeProcessing(e)
          select e;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...