2010-08-25 1 views

ответ

122

Ключевое слово dynamic используется для объявления переменных, которые должны быть связаны поздним сроком действия.
Если вы хотите использовать последнее связывание, для любого реального или воображаемого типа вы используете ключевое слово dynamic, а компилятор сделает все остальное.

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

IDynamicMetaObjectProvider interface позволяет классу взять под свой контроль его поведение в поздней степени.
Когда вы используете ключевое слово dynamic для взаимодействия с реализацией IDynamicMetaObjectProvider, DLR вызывает методы IDynamicMetaObjectProvider, и сам объект решает, что делать.

Классы ExpandoObject и DynamicObject являются реализациями IDynamicMetaObjectProvider.

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

+2

Что было бы хорошим местом, чтобы узнать больше об этом? Не API, а почему API? например Почему ExpandoObject не получается из DynamicObject, который ищет базовый тип defacto для программирования на основе метода ruby's method_missing. – Gishu

+3

Не могли бы вы добавить примеры использования, где это возможно? Например, как я могу использовать DynamicObject и какие преимущества? –

+6

Отличные ответы без примеров, подобных этому, похожи на торт без крема на вершине. –

32

В соответствии со спецификацией языка C# dynamic является декларацией типа. То есть dynamic x означает, что переменная x имеет тип dynamic.

DynamicObject - это тип, который упрощает реализацию IDynamicMetaObjectProvider и, таким образом, переопределяет специфическое поведение привязки для типа.

ExpandoObject - это тип, который действует как мешок имущества. То есть вы можете добавлять свойства, методы и т. д. к динамическим экземплярам этого типа во время выполнения.

+17

'dynamic' не фактический тип ... это просто намек, чтобы сообщить компилятору использовать позднее связывание для этой переменной. «Динамические» переменные фактически объявляются как «объект» в MSIL –

+0

@Thomas: с точки зрения компилятора это тип, но вы правы, что представление времени исполнения представляет собой объект Object. В нескольких презентациях MS вы найдете утверждение «статически типизированное как динамическое». –

+2

@Thomas: и спецификация языка говорит: «C# 4.0 представляет новый статический тип, называемый динамическим». –

20

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

Очень быстро, dynamic - это ключевое слово. Это не тип per-se. Это ключевое слово, которое сообщает компилятору игнорировать проверку статического типа во время разработки и вместо этого использовать позднюю привязку во время выполнения. Поэтому в оставшейся части ответа мы не будем тратить много времени на dynamic.

ExpandoObject и DynamicObject действительно являются типами. На ПОВЕРХНОСТИ они выглядят очень похожими друг на друга. Оба класса реализуют IDynamicMetaObjectProvider. Однако, копайте глубже, и вы обнаружите, что они совсем не похожи.

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

  1. DynamicObject не может быть сконструирован напрямую.
  2. Вы ДОЛЖНЫ расширить DynamicObject, чтобы он был полезен вам как разработчик.
  3. При расширении DynamicObject теперь вы можете предоставить ПОЛЬЗОВАТЕЛЬСКОЕ поведение относительно того, как вы хотите, чтобы динамическая отправка была разрешена для данных, хранящихся внутри вашего базового представления данных во время выполнения.
  4. ExpandoObject хранит базовые данные в словаре и т. Д. Если вы реализуете DynamicObject, вы можете хранить данные везде, где угодно и как угодно. (например, как вы получаете и устанавливаете данные при отправке, полностью зависит от вас).

Вкратце, используйте DynamicObject, если вы хотите создать свои СОБСТВЕННЫЕ типы, которые можно использовать с DLR, и работать с любыми CUSTOM поведением, которые вы хотели бы.

Пример: Представьте, что вы хотите иметь динамический тип, который возвращает настраиваемый по умолчанию всякий раз, когда попытка получения выполняется над членом, который НЕ существует (т. Е. Не был добавлен во время выполнения). И этот дефолт скажет: «Извините, в этой банке нет куки!». Если вам нужен динамический объект, который ведет себя так, вам нужно будет контролировать, что происходит, когда поле не найдено. ExpandoObject не позволит вам это сделать. Поэтому вам нужно создать свой собственный тип с уникальным поведением динамического члена (диспетчеризации) и использовать его вместо готового ExpandoObject.

Вы можете создать тип следующим образом: (. Примечание, приведенный ниже код только для иллюстрации и не может работать, чтобы узнать о том, как правильно использовать DynamicObject, есть много статей и руководств в другом месте.)

public class MyNoCookiesInTheJarDynamicObject : DynamicObject 
{ 
    Dictionary<string, object> properties = new Dictionary<string, object>(); 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     if (properties.ContainsKey(binder.Name)) 
     { 
      result = properties[binder.Name]; 
      return true; 
     } 
     else 
     { 
      result = "I'm sorry, there are no cookies in this jar!"; //<-- THIS IS OUR 
      CUSTOM "NO COOKIES IN THE JAR" RESPONSE FROM OUR DYNAMIC TYPE WHEN AN UNKNOWN FIELD IS ACCESSED 
      return false; 
     } 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     properties[binder.Name] = value; 
     return true; 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     dynamic method = properties[binder.Name]; 
     result = method(args[0].ToString(), args[1].ToString()); 
     return true; 
    } 
} 

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

dynamic d = new MyNoCookiesInTheJarDynamicObject(); 
var s = d.FieldThatDoesntExist; 

//in our contrived example, the below should evaluate to true 
Assert.IsTrue(s == "I'm sorry, there are no cookies in this jar!") 

ExpandoObject является полная реализация IDynamicMetaObjectProvider, где .NET Framework команда сделала все эти решения для вас. Это полезно, если вам не нужно какое-либо индивидуальное поведение, и вы чувствуете, что ExpandoObject работает достаточно хорошо для вас (90% времени, ExpandoObject достаточно хорош). Так, например, см. Следующее, а для ExpandoObject разработчики выбрали исключение, если динамический член не существует.

dynamic d = new ExpandoObject(); 

/* 
The ExpandoObject designers chose that this operation should result in an 
Exception. They did not have to make that choice, null could 
have been returned, for example; or the designers could've returned a "sorry no cookies in the jar" response like in our custom class. However, if you choose to use 
ExpandoObject, you have chosen to go with their particular implementation 
of DynamicObject behavior. 
*/ 

try { 
var s = d.FieldThatDoesntExist; 
} 
catch(RuntimeBinderException) { ... } 

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

Принимая во внимание, что DyanmicObject является вспомогательным BaseType, который упрощает и упрощает реализацию ваших собственных типов с уникальным динамическим поведением.

A useful tutorial on which much of the example source above is based.

0

выше пример DynamicObject не сказать различие ясно, потому что это в основном реализует функциональность, которая уже предоставленной ExpandoObject.

В двух ссылках, упомянутых ниже, очень ясно, что с помощью DynamicObject можно сохранить/изменить фактический тип (в примере, используемом в ссылках ниже) и лучше контролировать свойства и методы.

https://blogs.msdn.microsoft.com/csharpfaq/2009/09/30/dynamic-in-c-4-0-introducing-the-expandoobject/

https://blogs.msdn.microsoft.com/csharpfaq/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject/

public class DynamicXMLNode : DynamicObject 

{ 

    XElement node; 

    public DynamicXMLNode(XElement node) 

    { 

     this.node = node; 

    } 

    public DynamicXMLNode() 

    { 

    } 

    public DynamicXMLNode(String name) 

    { 

     node = new XElement(name); 

    } 

    public override bool TrySetMember(

     SetMemberBinder binder, object value) 

    { 

     XElement setNode = node.Element(binder.Name); 

     if (setNode != null) 

      setNode.SetValue(value); 

     else 

     { 

      if (value.GetType() == typeof(DynamicXMLNode)) 

       node.Add(new XElement(binder.Name)); 

      else 

       node.Add(new XElement(binder.Name, value)); 

     } 

     return true; 

    } 

    public override bool TryGetMember(
     GetMemberBinder binder, out object result) 

    { 

     XElement getNode = node.Element(binder.Name); 

     if (getNode != null) 

     { 

      result = new DynamicXMLNode(getNode); 

      return true; 

     } 

     else 

     { 

      result = null; 

      return false; 

     } 

    } 

} 

 Смежные вопросы

  • Нет связанных вопросов^_^