2009-06-01 16 views
16

me parece escribir este código una y otra vez y quería ver si había una mejor manera de hacerlo de manera más genérica.Manera elegante de ir de la lista de objetos al diccionario con dos de las propiedades

comienzo con una lista de Foo objetos

Foo[] foos = GenerateFoos(); 

Creo que quieren crear un diccionario donde la clave y el valor son las dos propiedades de Foo

por ejemplo:

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

existe de todos modos de escribir este código genéricamente, ya que parece una plantilla básica donde hay una matriz de objetos, una propiedad de clave, una propiedad de valor y un diccionario.

¿Alguna sugerencia?

estoy utilizando VS 2005 (C#, 2,0)

Respuesta

54

Con LINQ:

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

(y sí, fooDict es Dictionary<string, string>)


de edición para mostrar el dolor en VS2005:

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

donde se tiene (en Program):

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

cualquier cosa que funciona en VS2005? – leora

+0

Bueno, podrías escribir algo similar usando métodos anónimos y una clase de utilidad, pero probablemente sería más trabajo que tu código actual ... –

+0

Oh, eso es bueno.Mucho mejor que el mío :( –

6

Si está utilizando Framework 3.5, puede utilizar la ToDictionary extensión:

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

Para Framework 2.0, el código es casi tan simple como puede ser

Puede mejorar el rendimiento un poco mediante la especificación de la capacidad para el diccionario cuando se crea, por lo que no tiene que hacer ningún reasignaciones mientras que usted lo llene:

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

todo lo que funciona en VS2005? – leora

2

Sin LINQ, sin , no hay ayudantes incorporados para esto. Se puede escribir uno sin embargo:

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

No se ve tan elegante como las respuestas basadas en LINQ, lo hace ...

+0

Tendría que verificar, pero es posible que deba especificar los tipos genéricos. ... la inferencia de tipo genérico se hizo más fuerte en C# 3.0 (no fue tan buena en C# 2.0/VS2005) –

+0

Estoy bastante seguro de que la inferencia de tipo genérico fue en 2.0, pero la inferencia de delegado no fue, si fue, Podrías dejar caer el "nuevo Func ". –

+0

Por supuesto, siempre me olvido de lo que es esto en el 2.0 - Solo dejo que las quejas del compilador sean mi dispositivo de memoria :) –

1

Aquí es una solución que sea compatible con .NET 2.0 que utiliza System.Web .UI.Databinder para hacer la reflexión sobre el nombre de la propiedad: pierde la verificación del tipo en tiempo de compilación.

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

Se podría llamar de la siguiente manera:

Dictionary<string, string> fooDict = ToDictionary(foos, "Name", "StreetAddress"); 
Cuestiones relacionadas