Gibt es Pläne für „do“ / Aktion LINQ Operator?
Frage
Hier ist eine einfache Methode, mit einer foreach
Schleife:
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;
}
Art hässlich. Wenn es einige Betreiber in LINQ waren, die „etwas tun“ bedeuten (zum Beispiel eine Action
für jeden in der LINQ-Anweisung ausgewählt ausführen), wäre es schöner aussehen, mehr kurz und bündig:
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;
}
Ich weiß, das ist subjektiv, und meiner Meinung nach einfach. Für eine foreach-Schleife, die eine Linie hat, die einfach eine Methode aufruft, macht ein „do
“ Operator Sinn, meiner Meinung nach. Aber ich frage mich, ob jemand bei MS das gleiche gedacht hat. Ist ein solcher LINQ Operator in zukünftigen Versionen geplant (zum Beispiel neben dem C # 4.0 Debüt)?
Hier ist ein weiteres Beispiel mit einem Prädikat, wo der fiktive do
Operator wirklich den Code sehen Reiniger machen würde. Dies:
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. folgt aus:
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;
}
Lösung
Nein, ich erwarte keine direkte Sprache suport (das heißt innerhalb der Abfragesyntax) jederzeit bald.
Es klingt wie Sie die mythische ForEach
Erweiterungsmethode bedeuten; trivial hinzufügen, aber Eric Lippert unzählige Male über die Kreuzung zwischen nebenwirkungsfreie Funktionscode und Action<T>
mit Nebenwirkungen hat kommentiert. Insbesondere sind C # 3.0 / NET 3.5 Ausdrucksbäume lousy an Neben effecs (full lambda Unterstützung heikel machen). Die Runtime-Seite ist viel besser in .NET 4.0 , aber es ist unklar, zur Zeit, wie viel davon wird es in die Sprache (Lambda-Compiler) macht in C # 4.0.
Alles, was Sie (für Delegierten Version) benötigen, ist:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{ // note: omitted arg/null checks
foreach(T item in source) { action(item); }
}
Dann von jeder Abfrage können Sie einfach .ForEach(x => /* do something */)
verwenden.
Andere Tipps
Für Ihr spezielles Beispiel (Bestücken eines List<XElement>
), würde ich es auf diese Weise tun.
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;
}
Auch:. Vergessen Sie nicht, dass List<T>
bereits .ForEach<T>()
implementiert, so dass es zu verwenden, gegen jede Enumerable<T>
, das ist der gesamte Code Sie benötigen
myEnumerable.ToList().ForEach( x => myAction(x) );
Ich glaube nicht, das ist zu hart oder vielleicht bin ich etwas fehlt ...
IEnumerable<XElement> FieldsToXElements(object instance)
{
return instance.GetType()
.GetFields(instance)
.Select( f => new XElement( f.Name,
f.GetValue(instance) ) );
}
Wenn Sie einfach nur schauen, um eine Funktion aus Ihrer Linq-Anweisung zu rufen, dann können Sie bereits das tun, können Sie einen Anruf tätigen, um eine Funktion in einer Let Zuordnung.
var qry = from e in somelist
let errorcode = DoSomeProcessing(e)
select e;