Qualche piano per l'operatore & # 8220; do & # 8221; / Action LINQ?
Domanda
Ecco un metodo semplice con un ciclo 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;
}
Un po 'brutto. Se ci fosse qualche operatore in LINQ che significa "fai qualcosa" (ad es. esegui un Azione
per ciascuno selezionato nell'istruzione LINQ), sembrerebbe più bello, più conciso:
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;
}
Mi rendo conto che è soggettivo e solo la mia opinione. Per un ciclo foreach che ha una riga che invoca semplicemente un metodo, un " do
" operatore ha senso, secondo me. Ma mi chiedo se qualcuno in MS abbia pensato la stessa cosa. Tale operatore LINQ è previsto nelle prossime versioni (ad es. Accanto al debutto in C # 4.0)?
Ecco un altro esempio, con un predicato, in cui l'operatore fittizio do
renderebbe il codice più pulito. Questo:
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. in questo modo:
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;
}
Soluzione
No, non mi aspetto alcun
Sembra che tu intenda il mitico metodo di estensione ForEach
; banale da aggiungere, ma Eric Lippert ha commentato numerose volte l'incrocio tra codice funzionale privo di effetti collaterali e Azione < T >
con effetti collaterali. In particolare, gli alberi delle espressioni C # 3.0 / .NET 3.5 sono pessimi in termini di effetti collaterali (rendendo complicato il supporto completo lambda). Il lato runtime è molto meglio in .NET 4.0 , ma non è chiaro al momento, quanto di tutto ciò verrà inserito nel linguaggio (compilatore lambda) in C # 4.0.
Tutto ciò che serve (per la versione delegata) è:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{ // note: omitted arg/null checks
foreach(T item in source) { action(item); }
}
Quindi da qualsiasi query puoi semplicemente usare .ForEach (x = > / * fare qualcosa * /)
.
Altri suggerimenti
Per il tuo esempio specifico (compilando un Elenco < XElement >
), lo farei in questo modo.
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;
}
Inoltre: non dimenticare che Elenca < T >
implementa già . ;
, questo è tutto il codice che ti serve.
myEnumerable.ToList().ForEach( x => myAction(x) );
Non penso che sia troppo difficile o forse mi manca qualcosa ...
IEnumerable<XElement> FieldsToXElements(object instance)
{
return instance.GetType()
.GetFields(instance)
.Select( f => new XElement( f.Name,
f.GetValue(instance) ) );
}
Se stai semplicemente cercando di chiamare una funzione dall'istruzione linq, puoi già farlo, puoi effettuare una chiamata a una funzione in un compito Let.
var qry = from e in somelist
let errorcode = DoSomeProcessing(e)
select e;