2012-06-25 19 views
5

Tengo un IEnumerable<KeyValuePair<string,string>>, del cual me gustaría, idealmente, un objeto anónimo que tenga las claves como nombres de propiedad y los valores como valores de propiedad.Convertir KeyValuePair al tipo anónimo en una consulta LINQ

He intentado varias expresiones de selección (ninguna de las cuales compiló ...) y un enfoque que usa ExpandoObject (ver a continuación), pero sin éxito. ¿Existe una forma correcta de hacer esto? Si es posible, me gustaría evitar una iteración explícita adicional sobre la colección (es decir, hacerlo todo con una declaración LINQ de algún tipo).

Esto es lo que he intentado hasta ahora. Espero que también aclara lo que estoy tratando de hacer:

var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>> 

dynamic o = new ExpandoObject(); 
foreach (var kvp in kvps) 
{ 
    o.Add(kvp); 
} 

Esto está bien en tiempo de compilación, pero en tiempo de ejecución consigo un YSOD indicando 'System.Dynamic.ExpandoObject' no contiene una definición para ' Agregar ' - Supongo que funciona en tiempo de compilación porque o es dinámico, por lo que el compilador no puede saber si se le ha agregado un método .Add() desde que se creó la instancia. Lo curioso es que en el MSDN documenation page for ExpandoObject.Add() figura como uno de varios "métodos de interfaz implementados explícitamente".

No es necesario que lo incluya en un objeto dinámico; solo necesito obtener algo que tenga nombres de propiedad y valores de acuerdo con las claves y valores de los pares clave-valor.

Actualización: Bueno, esto es embarazoso. Resulta que esto también fue un problema XY.

Estoy tratando de renderizar esto a JSON utilizando las funciones incorporadas de ASP.NET MVC, simplemente devolviendo Json(data) en mi controlador. Las respuestas todo funcionaba muy bien para hacer lo primero pedí, pero cuando pase este objeto como data Todavía no consiguen lo que quiero:

// What I get: 
[ 
    { Key: 'firstkey', Value: 'FirstValue' }, 
    { Key: 'secondKey', Value: 'secondValue' } 
] 

// What I want: 
{ firstKey: 'FirstValue', secondKey: 'secondValue' } 

Al parecer, un ExpandoObject con las propiedades relevantes añadido no lo hizo cortarlo - que fue arrojado a un diccionario antes de renderizar ...

+1

Y sí, he visto [esta pregunta] (http://stackoverflow.com/questions/4685575/converting-a-keyvaluepair-collection-in-to-anonymous-type). Eso fue realmente un [problema XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), que se resolvió sin ayudarme. –

Respuesta

4

ExpandoObject implementa explícitamente IDictionary<string, object> - Así que hay que echarlo a una primera:

var kvps = getProps(); 
dynamic o = new ExpandoObject(); 
var dict = o as IDictionary<string, object>; 
foreach (var kvp in kvps) 
{ 
    dict.Add(kvp.Key, kvp.Value); 
} 

Ahora puede utilizar o como era de esperar:

var example = o.YourKey; 

Estoy tratando de renderizar esto a JSON utilizando las funciones incorporadas de ASP.NET MVC, simplemente devolviendo Json (datos) en mi controlador.

Interesante.

Para hacer eso, serializas un diccionario, no un ExpandoObject. El serializador JSON de MVC 3 ya lo hace con un diccionario.Todo lo que tiene que hacer es convertir su IEnumerable<KeyValuePair<string, object>> a un diccionario:

var kvps = getProps(); 
var dictionary = kvps.ToDictionary(k => k.Key, v => v.Value); 
return Json(dictionary, JsonRequestBehavior.AllowGet); //take out allow get if you don't need it. 

No hay dinámicas requeridas.

+0

Gracias! Sin embargo, estaba un poco rápido para formular mi problema. Consulte mi actualización ... –

+0

@TomasLycken Actualizado. – vcsjones

+0

¡Fantástico! ¡Muchas gracias! =) –

6

es necesario utilizar el ExpandoObject como IDictionary<string, object> mientras poblarlo:

var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>> 

IDictionary<string, object> o = new ExpandoObject(); 
foreach (var kvp in kvps) 
{ 
    // Or use Add(kvp.Key, kvp.Value), if you want 
    o[kvp.Key] = kvp.Value; 
} 

dynamic d = o; 
// Now you can use the properties 
+0

Esto me da un error de compilación en la primera línea ('IDictionary o = new ExpandoObject();'), pero dado que es usted, supongo que el compilador está equivocado. Supongo que piensa que debería ser 'IDictionary ' - Inmediatamente le diré que dijiste que lo hicieras de esta manera. –

+0

Allí, ahora funciona =) –

+0

... pero no del todo. Por favor mira mi actualización –

1

yo creo que hay que emitir su objeto expando a IDictionary y llamar Add (String, Object)

Cuestiones relacionadas