2009-10-24 8 views
35

Es posible en C# crear System.Collections.Generic.Dictionary<TKey, TValue> donde TKey es clase no condicionada y TValue - una clase anónima con varias propiedades, por ejemplo, nombre de columna de base de datos y su nombre localizado.Un diccionario donde el valor es un tipo anónimo en C#

Algo como esto:

new { ID = 1, Name = new { Column = "Dollar", Localized = "Доллар" } } 
+0

Muy similar (con LINQ): [Una lista genérica de clase anónima] (http://stackoverflow.com/questions/612689/a-generic-list- of-anonymous-class) – nawfal

+0

.Seleccione (...). AsEnumerable(). ToDictionary (k => k.id, v => v como objeto) funcionó para mí. Mi variable era Dictionary Ravi

+0

@Ravishankar: No necesitas 'AsEnumerable()' aquí, muy probablemente. No agrega nada en la parte superior de 'Seleccionar()'. – abatishchev

Respuesta

38

no se puede declarar un tal tipo de diccionario directamente (hay kludges pero estos son para propósitos de entretenimiento y de la novedad solamente), pero si sus datos proviene de un IEnumerable o IQueryable fuente, se puede conseguir uno usando el operador de LINQ ToDictionary y que sobresale la tecla deseada y el valor (de forma anónima escrito) de los elementos de la secuencia:

var intToAnon = sourceSequence.ToDictionary(
    e => e.Id, 
    e => new { e.Column, e.Localized }); 
16

Como itowlsonsaid, no se puede declarar una bestia, pero de hecho puede crear uno:

static IDictionary<TKey, TValue> NewDictionary<TKey, TValue>(TKey key, TValue value) 
{ 
    return new Dictionary<TKey, TValue>(); 
} 

static void Main(string[] args) 
{ 
    var dict = NewDictionary(new {ID = 1}, new { Column = "Dollar", Localized = "Доллар" }); 
} 

No está claro por qué usted realmente desea uso código como este.

+10

¿Por qué? Puedo pensar en una serie de razones. Aquí hay uno. Considere por ejemplo un diccionario utilizado para memorizar una función n-aria, digamos una función de cuatro argumentos int. En la próxima versión del CLR, por supuesto, usaría una tupla de 4, pero en C# 3, podría crear un diccionario de tipo anónimo {int, int, int, int}, hecho, sin necesidad de definir su propio tipo de tupla –

+9

Ahora tengo otra entrada para la sección "pinceles con fama" de mi página personal. :-) –

3

Usted puede hacer una reflexión

public static class ObjectExtensions 
{ 
    /// <summary> 
    /// Turn anonymous object to dictionary 
    /// </summary> 
    /// <param name="data"></param> 
    /// <returns></returns> 
    public static IDictionary<string, object> ToDictionary(this object data) 
    { 
     var attr = BindingFlags.Public | BindingFlags.Instance; 
     var dict = new Dictionary<string, object>(); 
     foreach (var property in data.GetType().GetProperties(attr)) 
     { 
      if (property.CanRead) 
      { 
       dict.Add(property.Name, property.GetValue(data, null)); 
      } 
     } 
     return dict; 
    } 
} 
+0

Buena idea. También puede hacerlo genérico: 'public static IDictionary ToDictionary (esta información del objeto) {}' – abatishchev

3

Creo ASP.NET MVC no lo hizo salir en el momento en que se hizo esta pregunta. Convierte objetos anónimos a diccionarios internamente.

Solo echa un vistazo al HtmlHelper class, por ejemplo. El método que traduce objetos a diccionarios es el AnonymousObjectToHtmlAttributes. Sin embargo, es específico para MVC y devuelve RouteValueDictionary.

Si quieres algo más genérico, intente esto:

public static IDictionary<string,object> AnonymousObjectToDictionary(object obj) 
{ 
    return TypeDescriptor.GetProperties(obj) 
     .OfType<PropertyDescriptor>() 
     .ToDictionary(
      prop => prop.Name, 
      prop => prop.GetValue(obj) 
     ); 
} 

Uno advatages intersting de esta aplicación es que devuelve un diccionario vacío para null objetos.

Y aquí es una versión genérica:

public static IDictionary<string,T> AnonymousObjectToDictionary<T>(
    object obj, Func<object,T> valueSelect 
) 
{ 
    return TypeDescriptor.GetProperties(obj) 
     .OfType<PropertyDescriptor>() 
     .ToDictionary<PropertyDescriptor,string,T>(
      prop => prop.Name, 
      prop => valueSelect(prop.GetValue(obj)) 
     ); 
} 
+0

¡Gracias por saberlo! La desventaja de tal método que puedo nombrar es usar la reflexión. – abatishchev

+0

@abatishchev Creo que es imposible resolver el problema sin reflexión. No estoy seguro, pero leer propiedades con TypeDescriptor podría ser más eficiente que con un .GetType(). GetProperties() regular. Por cierto, utilicé ILSpy en HtmlHelper y hace casi exactamente lo mismo. – jpbochi

Cuestiones relacionadas