Каковы истинные преимущества ExpandoObject? - PullRequest
556 голосов
/ 31 октября 2009

Класс ExpandoObject , добавляемый в .NET 4, позволяет произвольно устанавливать свойства объекта во время выполнения.

Есть ли в этом какие-либо преимущества перед использованием Dictionary<string, object> или даже Hashtable ? Насколько я могу судить, это не что иное, как хеш-таблица, к которой вы можете получить доступ с немного более лаконичным синтаксисом.

Например, почему это так:

dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);

Действительно лучше или существенно отличается от:

var obj = new Dictionary<string, object>();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";

Console.WriteLine(obj["MyString"]);

Какие реальные преимущества получаются при использовании ExpandoObject вместо простого использования произвольного типа словаря, если не очевидно, что вы используете тип, который будет определен во время выполнения.

Ответы [ 10 ]

658 голосов
/ 02 ноября 2009

Поскольку я написал статью MSDN, на которую вы ссылаетесь, я думаю, что должен ответить на нее.

Во-первых, я ожидал этого вопроса, и поэтому я написал сообщение в блоге, в котором показан более или менее реальный вариант использования ExpandoObject: Dynamic в C # 4.0: введение в ExpandoObject .

Вскоре ExpandoObject может помочь вам создать сложные иерархические объекты. Например, представьте, что у вас есть словарь в словаре:

Dictionary<String, object> dict = new Dictionary<string, object>();
Dictionary<String, object> address = new Dictionary<string,object>();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary<string,object>)dict["Address"])["State"]);

Чем глубже иерархия, тем страшнее код. С ExpandoObject он остается элегантным и читабельным.

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);

Во-вторых, как уже указывалось, ExpandoObject реализует интерфейс INotifyPropertyChanged, который дает вам больший контроль над свойствами, чем словарь.

Наконец, вы можете добавить события в ExpandoObject, как здесь:

class Program
{
   static void Main(string[] args)
   {
       dynamic d = new ExpandoObject();

       // Initialize the event to null (meaning no handlers)
       d.MyEvent = null;

       // Add some handlers
       d.MyEvent += new EventHandler(OnMyEvent);
       d.MyEvent += new EventHandler(OnMyEvent2);

       // Fire the event
       EventHandler e = d.MyEvent;

       if (e != null)
       {
           e(d, new EventArgs());
       }

       // We could also fire it with...
       //      d.MyEvent(d, new EventArgs());

       // ...if we knew for sure that the event is non-null.
   }

   static void OnMyEvent(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent fired by: {0}", sender);
   }

   static void OnMyEvent2(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent2 fired by: {0}", sender);
   }
}
74 голосов
/ 31 октября 2009

Одно преимущество - для обязательных сценариев. Сетки данных и сетки свойств будут подбирать динамические свойства через систему TypeDescriptor. Кроме того, привязка данных WPF будет понимать динамические свойства, поэтому элементы управления WPF могут связываться с ExpandoObject более легко, чем словарь.

Совместимость с динамическими языками, которые будут ожидать свойства DLR, а не словарные записи, также может быть рассмотрена в некоторых сценариях.

42 голосов
/ 01 июля 2011

Настоящим преимуществом для меня является абсолютно легкое связывание данных из XAML:

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

 <TextBlock Text="{Binding SomeData.WhatEver}" />
27 голосов
/ 31 октября 2009

Взаимодействие с другими языками, основанными на DLR, - причина, по которой я могу думать. Вы не можете передать им Dictionary<string, object>, поскольку это не IDynamicMetaObjectProvider. Еще одно дополнительное преимущество заключается в том, что он реализует INotifyPropertyChanged, что означает, что в мире привязки данных WPF он также имеет дополнительные преимущества, помимо того, что Dictionary<K,V> может предоставить вам.

19 голосов
/ 31 октября 2009

Все дело в удобстве программиста. Я могу себе представить написание быстрых и грязных программ с этим объектом.

14 голосов
/ 31 октября 2009

Я думаю, что это будет иметь синтаксическое преимущество, поскольку вы больше не будете "подделывать" динамически добавленные свойства с помощью словаря.

Это и взаимодействие с динамическими языками, я думаю.

11 голосов
/ 26 ноября 2014

Это пример из замечательной статьи MSDN об использовании ExpandoObject для создания динамических специальных типов для входящих структурированных данных (например, XML, Json).

Мы также можем назначить делегата для динамического свойства ExpandoObject :

dynamic person = new ExpandoObject();
person.FirstName = "Dino";
person.LastName = "Esposito";

person.GetFullName = (Func<String>)(() => { 
  return String.Format("{0}, {1}", 
    person.LastName, person.FirstName); 
});

var name = person.GetFullName();
Console.WriteLine(name);

Таким образом, это позволяет нам вводить некоторую логику в динамический объект во время выполнения. Поэтому вместе с лямбда-выражениями, замыканиями, динамическим ключевым словом и классом DynamicObject мы можем ввести некоторые элементы функционального программирования в наш код на C #, который мы знаем по динамическим языкам как JavaScript или PHP.

4 голосов
/ 10 апреля 2013

В некоторых случаях это удобно. Я буду использовать его, например, для модульной оболочки. Каждый модуль определяет свой собственный диалог конфигурации, связанный с его настройками. Я предоставляю ему ExpandoObject в качестве Datacontext и сохраняю значения в моей конфигурации Storage. Таким образом, средство записи диалогового окна конфигурации просто привязывается к значению, и оно автоматически создается и сохраняется. (И предоставлены модулю для использования этих настроек, конечно)

Это проще в использовании, чем словарь. Но каждый должен знать, что внутренне это просто словарь.

Это походит на LINQ только синтаксический сахар, но иногда это облегчает.

Итак, чтобы ответить на ваш вопрос напрямую: его легче писать и легче читать. Но технически это, по сути, Dictionary<string,object> (вы даже можете привести его к одному для получения списка значений).

0 голосов
/ 22 декабря 2017

После valueTuples, что за класс ExpandoObject? это 6 строк кода с ExpandoObject:

dynamic T = new ExpandoObject();
T.x = 1;
T.y = 2;
T.z = new ExpandoObject();
T.z.a = 3;
T.b= 4;

можно записать в одну строку с кортежами:

var T = (x: 1, y: 2, z: (a: 3, b: 4));

кроме того, с синтаксисом кортежа вы имеете строгий вывод типов и поддержку intlisense

0 голосов
/ 05 февраля 2016
var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

Я думаю, что это работает только потому, что у всего есть ToString (), в противном случае вам нужно будет знать, какой это был тип, и привести «объект» к этому типу.


Некоторые из них полезны чаще других, я стараюсь быть тщательным.

  1. Гораздо более естественным может быть доступ к коллекции, в данном случае это, по сути, «словарь» с использованием более точечной нотации.

  2. Кажется, это можно использовать как действительно хороший кортеж. Вы по-прежнему можете называть своих членов "Item1", "Item2" и т. Д. ... но теперь вам не нужно, это также изменчиво, в отличие от Tuple. Это имеет огромный недостаток отсутствия поддержки intellisense.

  3. Вам может быть неудобно с «именами элементов в виде строк», как и со словарем, вы можете почувствовать, что это слишком похоже на «выполнение строк», и это может привести к кодированию соглашений об именах, и работа с морфемами и слогами, когда код пытается понять, как использовать члены: -P

  4. Можете ли вы присвоить значение самому ExpandoObject или только его членам? Сравните и сопоставьте с динамическим / динамическим [], используйте в зависимости от ваших потребностей.

  5. Я не думаю, что dynamic / dynamic [] работает в цикле foreach, вам нужно использовать var, но, возможно, вы можете использовать ExpandoObject.

  6. Вы не можете использовать динамический как элемент данных в классе, возможно, потому что это по крайней мере что-то вроде ключевого слова, возможно, вы можете использовать с ExpandoObject.

  7. Я ожидаю, что он "является" ExpandoObject, может быть полезным для разметки очень общих вещей, с кодом, который различается по типам, где используется много динамических вещей.


Хорошо, если бы вы могли детализировать несколько уровней одновременно.

var e = new ExpandoObject();
e.position.x = 5;
etc...

Это не лучший пример, представьте себе элегантное использование в ваших собственных проектах.

Жаль, что вы не можете заставить код создавать некоторые из них и выдвигать результаты в intellisense. Я не уверен, как это будет работать.

Будьте хороши, если они могут иметь как ценность, так и членов.

var fifteen = new ExpandoObject();
fifteen = 15;
fifteen.tens = 1;
fifteen.units = 5;
fifteen.ToString() = "fifteen";
etc...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...