2017-12-07 3 views
3

Ich habe folgende Möglichkeiten Werte in einer Liste abrufen:Leistung dynamische vs Reflexion

Reflexion mit:

foreach (var item in items) { 
    var property=item.Fields[fieldName].GetType().GetProperty("Id"); 
    var value=property.GetValue(item.Fields[fieldName]); 
    if (value==searchValue) { 
     filtered.Add(item); 
    } 
} 

mit dynamisch:

foreach (var item in items) { 
    dynamic itemProperty=item.Fields[fieldName]; 
    if (itemProperty.Id==searchValue) { 
     filtered.Add(item); 
    } 
} 

Beiden Schleifen das gleiche tun. Sie filtern IEnumerable (oder List) nach Field [fieldName], die verschiedenen Typen aber alle eine Int-Eigenschaft namens "Id" enthalten können.

Ich frage mich, was würde man eine bessere Leistung haben. Zusätzlich: Würde eine Änderung der LinQ-Abfrage die Performance erhöhen?

+1

'dynamic' verwendet auch Reflektion, aber nicht auf so grobe Art und Weise wie in Ihrem ersten Beispiel. Also würde ich vermuten, dass Dynamik hier schneller sein wird. Natürlich hättest du das auch selbst messen können. – Evk

+2

gibt es eine viel einfachere Möglichkeit, diese Art von Szenario zu nähern - fügen Sie eine 'Schnittstelle IHasId {int Id {get; }} 'und lassen Sie es von Ihren Typen implementieren (was wegen impliziter Schnittstellenimplementierungen normalerweise nur bedeutet,' 'IHasId' 'zu jedem hinzuzufügen) ... dann' foreach (IHasId-Element in Elementen) {if (item.Id == searchValue) { ...}} –

+1

Warum probierst du es einfach nicht in einer großen Sammlung aus? Einfach * messen * es, z.B. Verwenden von 'StopWatch'. Und auch daran denken, nicht [vorzeitige Optimierung] (http://wiki.c2.com/?PrematureOptimization) zu tun. Sehen Sie sich auch https://stackoverflow.com/questions/4646786/dynamic-lang-runtime-vs-reflection an. – HimBromBeere

Antwort

4

Die einfachste Weg, dies zu tun IMO ist eine Schnittstelle zu definieren, die eine int Id {get;} Eigenschaft hat und Ihre Typen implementieren. Dann Code an die Schnittstelle. Wenn Ihr vorhandener Code generisch könnten Sie sogar in der Lage sein, eine where T : IYourInterface Einschränkung hinzuzufügen, aber Sie können auf IYourInterface oder so werfen (unter der Annahme T tatsächlich die Schnittstelle nicht implementiert).

Wenn Schnittstellen sind keine Option:

Reflexion und dynamic beide Gemeinkosten haben; dynamic hat eine bessere Optimierung (Wiederverwendung einer zwischengespeicherten Strategie).

Wenn Ihr items Liste ist stark an eine bestimmte getippt T (wo T hier unbekannt ist), dann können Sie möglicherweise dieses Konzept weiter optimieren LINQ Ausdrücke Delegierten zu kompilieren:

static class IdFetcher 
{ 
    public static int Fetch<T>(T item) => IdFetcher<T>.Fetch(item); 
} 
static class IdFetcher<T> 
{ 
    public static int Fetch(T item) => fetch(item); 
    static readonly Func<T, int> fetch; 
    static IdFetcher() 
    { 
     var p = Expression.Parameter(typeof(T), "item"); 
     fetch = Expression.Lambda<Func<T, int>>(
      Expression.PropertyOrField(p, "Id"), p).Compile(); 
    } 
} 

Dann benutzen Sie einfach IdFetcher<T>.Fetch(obj) oder IdFetcher.Fetch(obj) (die erste ist direkter; die zweite ist nützlich für anonyme Typen, wo Sie die T nicht angeben können)

Andere als das: wenn Sie möchte wissen, was schneller ist: Zeit sie (für eine große Anzahl von Iterationen).