Каковы истинные преимущества ExpandoObject?

Класс 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 вместо использования произвольного типа словаря, если не очевидно, что вы используете тип, который будет определен во время выполнения.

Ответ 1

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

Во-первых, я ожидал этого вопроса и поэтому написал сообщение в блоге, в котором показан более или менее реальный вариант использования ExpandoObject: Dynamic в С# 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);
   }
}

Ответ 2

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

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

Ответ 3

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

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

 <TextBlock Text="{Binding SomeData.WhatEver}" />

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

Это пример из замечательной статьи 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 мы можем ввести некоторые элементы функционального программирования в наш код на С#, которые мы знаем по динамическим языкам, таким как JavaScript или PHP.

Ответ 8

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

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

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

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

Ответ 9

var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

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


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

  • Возможно, гораздо более естественным является доступ к коллекции, в данном случае, что фактически является "словарем", используя более точную нотацию.

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

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

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

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

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

  • Я ожидаю, что это "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...

Ответ 10

После 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