Обрабатывать объект как словарь свойств в C # - PullRequest
16 голосов
/ 11 марта 2012

Я хочу иметь возможность доступа к значениям свойств в объекте, таком как словарь, используя имя свойства в качестве ключа.Мне все равно, возвращаются ли значения в виде объектов, поэтому Dictionary<string, object> хорошо.Это предполагаемое использование:

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

Я собирался реализовать свой собственный класс для этого, но потом я начал замечать, что классы, такие как DynamicObject, реализуют интерфейс IDictionary, что наводит на мысль, что это уже где-то делается для меня.

То, что я хочу, похоже на функциональность, используемую ASP.NET MVC, которая позволяет использовать анонимные типы для установки атрибутов тега HTML.У меня есть много классов, которые используют словари в качестве источников данных, но большую часть времени я должен иметь возможность передавать и объекты.

Так как это для универсальной библиотеки Я думал, что создам повторно используемый класс, который просто украшает объект с помощью интерфейса IDictionary.Это спасет меня от взрыва перегрузок.

Ответы [ 3 ]

19 голосов
/ 11 марта 2012

Я не верю, что такой встроенный тип .Net уже есть в .Net framework. Кажется, что вы действительно хотите создать объект, который ведет себя во многом как объект Javascript. Если это так, то вывод из DynamicObject может быть правильным выбором. Это позволяет вам создать объект, который, когда обернут в dynamic, позволяет связывать напрямую obj.Name или через индексатор 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;
  }
}

Вы можете использовать это для переноса любого типа и использовать как индексатор, так и синтаксис имени, чтобы получить свойства

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
8 голосов
/ 29 марта 2013

У меня есть этот метод расширения, вероятно, самый простой, который он может получить:

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

Теперь вы можете сделать:

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

Примечание:

  1. что этот словарь чувствителен к регистру (вы можете тривиально расширить его, пропустив правую StringComparer).

  2. что он игнорирует индексаторы (которые также являются свойствами), но вам решать над этим.

  3. , что метод не является универсальным, учитывая, что он не помогает в боксе, потому что внутренне он вызывает obj.GetType, поэтому в любом случае он блокируется.

  4. что вы получаете только «читаемые» свойства (иначе вы не получите значения, содержащиеся в нем). Так как вы хотите, чтобы он также был "доступным для записи", вы должны также использовать флаг CanWrite.

1 голос
/ 11 марта 2012

динамическое ключевое слово может быть одним из вариантов для вас. он использует динамический язык исполнения. Во время выполнения он пытается найти ближайший доступный тип в программе. Если он не может, тогда он преобразует динамический тип в объект dictionay, где key - это имя свойства, а value - значение свойства.

перейдите по ссылкам MSDN:

Использование динамического ключевого слова в C #
динамический (C # Reference)
Обзор DLR
использование динамического примера прохождения страницы

...