2012-03-11 56 views
14

Quiero poder acceder a valores de propiedad en un objeto como un diccionario, utilizando el nombre de la propiedad como clave. Realmente no me importa si los valores se devuelven como objetos, por lo que Dictionary<string, object> está bien. Esta es la intención de uso:Diccionario de Propiedades de objeto de objeto en C#

object person = new { Name: "Bob", Age: 45 }; 
IDictionary<string, object> lookup = new PropertyDictionary(person); 
string name = (string)person["Name"]; 
person["Age"] = (int)person["Age"] + 1; // potentially editable 

estaba a punto de poner en práctica mi propia clase para esto, pero luego empecé a notar clases como DynamicObject implementan la interfaz IDictionary, lo que hizo pensar que esto ya se está haciendo para mí en alguna parte.

Lo que quiero es similar a la funcionalidad utilizada por ASP.NET MVC que permite el uso de tipos anónimos para establecer atributos de etiquetas HTML. Tengo muchas clases que usan diccionarios como fuentes de datos, pero la mayoría de las veces también podría pasar objetos.

Dado que esto es para un propósito general library, pensé que crearía una clase reutilizable que simplemente decorara un objeto con la interfaz IDictionary. Me salvará de crear una explosión de sobrecargas.

+0

Algo así como la indización en MSDN ... http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx – Lloyd

Respuesta

18

que no creen que es un tipo incorporado .Net como esto ya en el marco .Net. Parece que realmente quieres crear un objeto que se comporte mucho como un objeto Javascript. Si es así, derivar de DynamicObject puede ser la elección correcta. Le permite crear un objeto que cuando se envuelve con dynamic le permite vincular directamente obj.Name o mediante el indexador obj["Name"].

public class PropertyBag : DynamicObject { 
    private object _source; 
    public PropertyBag(object source) { 
    _source = source; 
    } 
    public object GetProperty(string name) { 
    var type = _source.GetType(); 
    var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 
    return property.GetValue(_source, null); 
    } 
    public override bool TryGetMember(GetMemberBinder binder, out object result) { 
    result = GetProperty(binder.Name); 
    return true; 
    } 
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { 
    result = GetProperty((string)indexes[0]); 
    return true; 
    } 
} 

Usted puede usar esto para envolver cualquier tipo y utilizar tanto la sintaxis indexador y el nombre para obtener las propiedades

var student = new Student() { FirstName = "John", LastName = "Doe" }; 
dynamic bag = new PropertyBag(student); 
Console.WriteLine(bag["FirstName"]); // Prints: John 
Console.WriteLine(bag.FirstName);  // Prints: John 
+0

Hice algo similar, pero sin heredar DynamicObject. Acabo de heredar de IDictionary y solo apoyo la indexación, ya que eso es todo lo que necesito. –

+0

¿Has mirado ExpandoObject? http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx – Scott

+1

ExpandoObject solo funciona si está comenzando desde cero. –

1

palabra clave dinámica puede ser una opción para usted. usa tiempo de ejecución de lenguaje dinámico. En tiempo de ejecución, intenta hacer coincidir el tipo disponible más cercano en el programa. Si no puede, convierte el tipo dinámico en el objeto dictionay, donde la clave es el nombre de la propiedad y el valor es el valor de la propiedad.

siga estos enlaces de MSDN:

Using dynamic keyword in C#
dynamic (C# Reference)
DLR Overview
usage of dynamic sample walkthough page

+0

El único problema es que yo tendría que modificar todos mis implementaciones para aceptar una dinámica Además, no estoy seguro de cómo haría referencia a una propiedad por su nombre, ya que obj ["Nombre"] se interpretará como una llamada a un indexador en la dinámica. –

+0

¿No puedes ir directamente al diccionario? tener tu propia implementación puede hacer que las cosas se arruinen ... ¿Lo que intento es que quieras una clase que se convierta automáticamente en diccionario a través del indexador? ¿Has intentado crear el indexador con el parámetro de tipo string? – Uday0119

+0

Quiero envolver un objeto, no copiarlo en un diccionario. La idea es pasar un objeto donde se espera un IDictionary. De esa manera puedo usar tipos anónimos donde se esperan diccionarios. –

8

tengo este método de extensión, probablemente la más simple que puede conseguir:

public static Dictionary<string, object> ToPropertyDictionary(this object obj) 
{ 
    var dictionary = new Dictionary<string, object>(); 
    foreach (var propertyInfo in obj.GetType().GetProperties()) 
     if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0) 
      dictionary[propertyInfo.Name] = propertyInfo.GetValue(obj, null); 
    return dictionary; 
} 

Ahora se puede hacer:

object person = new { Name = "Bob", Age = 45 }; 
var lookup = person.ToPropertyDictionary(); 
string name = (string)lookup["Name"]; 
lookup["Age"] = (int)lookup["Age"] + 1; // indeed editable 

Nota:

  1. que este diccionario es entre mayúsculas y minúsculas (que puede trivialmente extenderlo pasando la derecha StringComparer).

  2. que ignora los indexadores (que también son propiedades) pero depende de usted trabajar en ello.

  3. que el método no es genérico porque no ayuda al boxeo porque internamente llama a obj.GetType, por lo que bloquea de todos modos en ese punto.

  4. que obtiene solo las propiedades "legibles" (de lo contrario, no obtiene los valores contenidos en ella). Como también desea que se pueda "escribir", también debe usar la bandera CanWrite.

Cuestiones relacionadas