Есть какие-нибудь планы относительно оператора LINQ “do” / Action?

StackOverflow https://stackoverflow.com/questions/476736

  •  20-08-2019
  •  | 
  •  

Вопрос

Вот простой метод с 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top