2009-06-01 5 views
16

Ich scheine diesen Code immer und immer wieder zu schreiben und wollte sehen, ob es einen besseren Weg gibt, es generischer zu machen.Eleganter Weg von einer Liste von Objekten zu einem Wörterbuch mit zwei der Eigenschaften zu gehen

ich mit einer Liste von Foo beginnen Objekte

Foo[] foos = GenerateFoos(); 

Ich denke, möchte ein Wörterbuch erstellen, wo der Schlüssel und Wert sind beide Eigenschaften von Foo

zum Beispiel:

Dictionary<string, string> fooDict = new Dictionary<string, string>(): 
foreach (Foo foo in foos) 
{ 
    fooDict[foo.Name] = foo.StreetAddress; 
} 

gibt es sowieso, diesen Code generisch zu schreiben, da es wie eine grundlegende Vorlage erscheint, wo es ein Array von Objekten, eine Schlüsseleigenschaft, eine Werteigenschaft und ein Wörterbuch gibt.

Irgendwelche Vorschläge?

Ich verwende VS 2005 (C#, 2,0)

Antwort

54

Mit LINQ:

var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress); 

(und ja, fooDict ist Dictionary<string, string>)


bearbeiten, den Schmerz zu zeigen, in VS2005:

Dictionary<string, string> fooDict = 
    Program.ToDictionary<Foo, string, string>(foos, 
     delegate(Foo foo) { return foo.Name; }, 
     delegate(Foo foo) { return foo.StreetAddress; }); 

, wo man (in Program) haben:

public static Dictionary<TKey, TValue> ToDictionary<TSource, TKey, TValue>(
    IEnumerable<TSource> items, 
    Converter<TSource, TKey> keySelector, 
    Converter<TSource, TValue> valueSelector) 
{ 
    Dictionary<TKey, TValue> result = new Dictionary<TKey, TValue>(); 
    foreach (TSource item in items) 
    { 
     result.Add(keySelector(item), valueSelector(item)); 
    } 
    return result; 
} 
+0

alles, was in VS2005 funktioniert? – leora

+0

Nun, Sie könnten etwas ähnliches mit anonymen Methoden und einem Dienstprogramm Klasse schreiben, aber es wäre wahrscheinlich mehr Arbeit als Ihr bestehender Code ... –

+0

Oh, das ist schön.Viel besser als meins :( –

6

Wenn Sie Framework 3.5 verwenden, können Sie die ToDictionary Erweiterung verwenden:

Dictionary<string, string> fooDict = foos.ToDictionary(f => f.Name, f => f.StreetAddress); 

Für framework 2.0, der Code ziemlich so einfach ist, wie es sein kann.

Sie können die Leistung etwas verbessern, indem die Kapazität für das Wörterbuch angeben, wenn Sie es schaffen, so dass es auch keine Umwidmungen zu tun haben, während Sie es füllen:

Dictionary<string, string> fooDict = new Dictionary<string, string>(foos.Count): 
+0

alles, was in VS2005 funktioniert? – leora

2

Ohne LINQ, nein Dafür gibt es keine eingebauten Helfer. Sie könnte man schreiben aber:

// I forget if you need this delegate definition -- this may be already defined in .NET 2.0 
public delegate R Func<T,R>(T obj); 
public static Dictionary<K,V> BuildDictionary<T,K,V>(IEnumerable<T> objs, Func<T,K> kf, Func<T,V> vf) 
{ 
    Dictionary<K,V> d = new Dictionary<K,V>(); 
    foreach (T obj in objs) 
    { 
     d[kf(obj)] = vf(obj); 
    } 
    return d; 
} 

Dictionary<string, string> fooDict = BuildDictionary(foos, new Func<Foo,string>(delegate(Foo foo) { return foo.Name; }), new Func<Foo,string>(delegate(Foo foo) { return foo.StreetAddress; })); 

Es ist nicht fast sieht so elegant wie die LINQ-basierten Antworten, tut es ...

+0

Ich würde überprüfen müssen, aber Sie könnten feststellen, dass Sie die generischen Typen angeben müssen. .. die generische Typinferenz wurde in C# 3.0 stärker (in C# 2.0/VS2005 war das nicht so toll) –

+0

Ich bin mir ziemlich sicher, dass die generische Typinferenz in 2.0 war, aber die Delegierteninferenz war nicht - wenn es war, du könntest den "neuen Func " Kram fallen lassen. –

+0

Natürlich, ich scheine immer zu vergessen, was von diesem Zeug in 2.0 ist - ich ließ nur die Beschwerden des Kompilers mein Gedächtnisgerät sein :) –

1

Hier ist eine Lösung, die .net 2.0-kompatibel ist, die System.Web verwendet .UI.Databinder, um die Reflektion über den Namen der Eigenschaft zu machen - Sie verlieren die Überprüfung der Kompilierzeit.

 public static Dictionary<string, string> ToDictionary<T>(List<T> list, string keyName, string valueName) 
    { 
     Dictionary<string, string> outputDictionary = new Dictionary<string, string>(); 
     foreach (T item in list) 
     { 
      string key = Eval<T, string>(item, keyName); 
      string value = Eval<T, string>(item, valueName); 
      output[key] = value; 
     } 

     return outputDictionary; 
    } 

    public static TOut Eval<TIn, TOut>(TIn source, string propertyName) 
    { 
     object o = DataBinder.GetPropertyValue(source, propertyName); 
     if (o is TOut) 
      return (TOut)o; 

     return default(TOut); 
    } 

Sie nennen würde, wie folgt:

Dictionary<string, string> fooDict = ToDictionary(foos, "Name", "StreetAddress"); 
Verwandte Themen