2009-01-24 8 views
11

Oto prosty sposób z foreach pętli:Wszelkie plany dotyczące operatora "do zrobienia/działania LINQ"?

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; 
} 

Niby brzydka. Gdyby istniał jakiś operator w LINQ to znaczy, że „coś zrobić” (np wykonać Action dla każdego wybranego w rachunku LINQ), to będzie wyglądać ładniej, bardziej lakoniczny:

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; 
} 

Zdaję sobie sprawę, że to subiektywne i tylko moje opinia. W przypadku pętli foreach, która ma jedną linię, która po prostu wywołuje metodę, operacja "do" ma sens, moim zdaniem. Ale zastanawiam się, czy ktoś w stwardnieniu rozsianym myślał to samo. Czy taki operator LINQ jest planowany w przyszłych wydaniach (np. Obok debiutu C# 4.0)?

Oto kolejny przykład z predykatem, w którym fikcyjny operator do naprawdę sprawiłby, że kod wyglądałby czystszy. To:

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; 
} 

vs. to:

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; 
} 

Odpowiedz

15

Nie, nie spodziewam się żadnego bezpośredniego język suport (czyli wewnątrz składni zapytań) w najbliższym czasie.

To brzmi jak masz na myśli mityczną metodę rozszerzenia ForEach; trywialne dodawanie, ale Eric Lippert wielokrotnie komentował, że kod funkcjonalny nie zawiera efektu ubocznego, a jego efekty uboczne to Action<T>. W szczególności, drzewa ekspresji C# 3.0/.NET 3.5 są kiepskie pod kątem side-effecs (utrudniając pełną obsługę lambda). Strona runtime is much better in .NET 4.0, ale w tej chwili nie jest jasne, jak dużo z tego zostanie wprowadzone do języka (kompilator lambda) w C# 4.0.

Wszystko czego potrzebujesz (dla wersji delegata) wynosi:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) 
{ // note: omitted arg/null checks 
    foreach(T item in source) { action(item); } 
} 

Następnie z każdej kwerendy można po prostu użyć .ForEach(x => /* do something */).

1

Nie sądzę, jest to zbyt trudne, a może coś mi brakuje ...

IEnumerable<XElement> FieldsToXElements(object instance) 
{ 
    return instance.GetType() 
        .GetFields(instance) 
        .Select(f => new XElement(f.Name, 
               f.GetValue(instance))); 
} 
+0

Zadanie jest banalne. Bardziej interesuje mnie "uroda" kodu. :) – core

1

Jeśli jesteś po prostu patrząc na wywołanie funkcji z poziomu rachunku linq potem można już zrobić możesz wykonać wywołanie funkcji w zadaniu Let.

var qry = from e in somelist 
      let errorcode = DoSomeProcessing(e) 
      select e; 
+0

Jedynym problemem jest tutaj DoSomeProcessing to Func <>, a nie Action <> :) – core

+0

Nieco piękne, ale podchwytliwe :) – Teejay

3

dla konkretnego przykładu (zapełnianie List<XElement>), zrobiłbym to w ten sposób.

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; 
} 

także: Nie zapominaj, że List<T> już implementuje .ForEach<T>(), tak aby wykorzystać go przeciwko jakiejkolwiek Enumerable<T>, to cały kod trzeba.

myEnumerable.ToList().ForEach(x => myAction(x)); 
+0

Bardzo ładne! Nie myślałem o tym.Chociaż skracałbym go nieco, wykonując tylko: return (z pola w ...) ToList() bez definiowania listy fieldElements. Dzięki jeszcze raz! – core

Powiązane problemy