2009-01-24 10 views
11

Voici une méthode simple avec une boucle foreach:Des plans pour "faire"/Action LINQ opérateur?

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

Type de laid. S'il y avait un certain opérateur LINQ que signifie « faire quelque chose » (par exemple, effectuer une Action pour chaque sélectionné dans la déclaration LINQ), il semble plus agréable, plus laconique:

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

Je me rends compte que ce subjectif, et que mon opinion. Pour une boucle foreach qui a une ligne qui invoque simplement une méthode, un opérateur "do" a du sens, à mon avis. Mais je me demande si quelqu'un à MS a pensé la même chose. Un tel opérateur LINQ est-il prévu dans les prochaines versions (par exemple, à l'occasion du lancement de C# 4.0)?

Voici un autre exemple, avec un prédicat, où l'opérateur fictif do rendrait le code plus net. Ce:

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

par rapport à ceci:

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

Répondre

15

Non, je ne pense pas la langue directe suport (à savoir dans la syntaxe de requête) dans un proche avenir.

Il semble que vous vouliez dire la mythique méthode d'extension ForEach; trivial à ajouter, mais Eric Lippert a commenté de nombreuses fois sur le croisement entre le code fonctionnel sans effet secondaire et Action<T> avec des effets secondaires. En particulier, les arborescences d'expression C# 3.0/.NET 3.5 sont minables en side-effecs (rendant le support lambda complet difficile). Le côté de l'exécution is much better in .NET 4.0, mais on ne sait pas pour le moment combien cela va faire dans la langue (compilateur lambda) en C# 4.0.

Tout ce que vous avez besoin (pour la version déléguée) est la suivante:

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

ensuite de toute requête, vous pouvez simplement utiliser .ForEach(x => /* do something */).

1

Je ne pense pas que cela à la recherche est trop difficile ou peut-être que je manque quelque chose ...

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

La tâche est triviale. Je suis plus intéressé par la "joliesse" du code. :) – core

1

Si vous êtes simplement à appeler une fonction à partir de votre déclaration de LINQ, vous pouvez déjà faire , vous pouvez faire un appel à une fonction dans une affectation Let.

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

Le seul problème ici est DoSomeProcessing est un Func <>, pas une action <> :) – core

+0

Un peu non-beau, mais délicat :) – Teejay

3

Pour votre exemple spécifique (alimenter une List<XElement>), je le ferais de cette façon.

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

aussi: Ne pas oublier que List<T> implémente déjà .ForEach<T>(), afin de l'utiliser contre toute Enumerable<T>, tout cela est le code dont vous avez besoin.

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

Très gentil! Je n'y ai pas pensé.Bien que je le raccourcisse légèrement en faisant juste: retour (de champ dans ...). ToList() sans définir Liste fieldElements. Merci encore! – core