В чем разница между System.Dynamic.ExpandoObject
, System.Dynamic.DynamicObject
и dynamic
?Различия между ExpandoObject, DynamicObject и динамическими
В каких ситуациях вы используете эти типы?
В чем разница между System.Dynamic.ExpandoObject
, System.Dynamic.DynamicObject
и dynamic
?Различия между ExpandoObject, DynamicObject и динамическими
В каких ситуациях вы используете эти типы?
Ключевое слово dynamic
используется для объявления переменных, которые должны быть связаны поздним сроком действия.
Если вы хотите использовать последнее связывание, для любого реального или воображаемого типа вы используете ключевое слово dynamic
, а компилятор сделает все остальное.
Когда вы используете ключевое слово dynamic
для взаимодействия с обычным экземпляром, DLR выполняет вызовы поздней связи с обычными методами экземпляра.
IDynamicMetaObjectProvider
interface позволяет классу взять под свой контроль его поведение в поздней степени.
Когда вы используете ключевое слово dynamic
для взаимодействия с реализацией IDynamicMetaObjectProvider
, DLR вызывает методы IDynamicMetaObjectProvider
, и сам объект решает, что делать.
Классы ExpandoObject
и DynamicObject
являются реализациями IDynamicMetaObjectProvider
.
ExpandoObject
- это простой класс, который позволяет добавлять членов в экземпляр и использовать их dynamic
союзник.
DynamicObject
- это более продвинутая реализация, которая может быть унаследована, чтобы легко обеспечить индивидуальное поведение.
В соответствии со спецификацией языка C# dynamic
является декларацией типа. То есть dynamic x
означает, что переменная x
имеет тип dynamic
.
DynamicObject
- это тип, который упрощает реализацию IDynamicMetaObjectProvider
и, таким образом, переопределяет специфическое поведение привязки для типа.
ExpandoObject
- это тип, который действует как мешок имущества. То есть вы можете добавлять свойства, методы и т. д. к динамическим экземплярам этого типа во время выполнения.
'dynamic' не фактический тип ... это просто намек, чтобы сообщить компилятору использовать позднее связывание для этой переменной. «Динамические» переменные фактически объявляются как «объект» в MSIL –
@Thomas: с точки зрения компилятора это тип, но вы правы, что представление времени исполнения представляет собой объект Object. В нескольких презентациях MS вы найдете утверждение «статически типизированное как динамическое». –
@Thomas: и спецификация языка говорит: «C# 4.0 представляет новый статический тип, называемый динамическим». –
Я попытаюсь дать более четкий ответ на этот вопрос, чтобы четко объяснить, какие различия между динамическими, ExpandoObject
и DynamicObject
.
Очень быстро, dynamic
- это ключевое слово. Это не тип per-se. Это ключевое слово, которое сообщает компилятору игнорировать проверку статического типа во время разработки и вместо этого использовать позднюю привязку во время выполнения. Поэтому в оставшейся части ответа мы не будем тратить много времени на dynamic
.
ExpandoObject
и DynamicObject
действительно являются типами. На ПОВЕРХНОСТИ они выглядят очень похожими друг на друга. Оба класса реализуют IDynamicMetaObjectProvider
. Однако, копайте глубже, и вы обнаружите, что они совсем не похожи.
DynamicObject - это частичная реализация IDynamicMetaObjectProvider
, предназначенная для того, чтобы стать отправной точкой для разработчиков, чтобы реализовать свои собственные типы, поддерживающие динамическую диспетчеризацию с пользовательскими базовыми функциями хранения и поиска, чтобы сделать динамическую диспетчерскую работу.
Вкратце, используйте 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.
выше пример DynamicObject
не сказать различие ясно, потому что это в основном реализует функциональность, которая уже предоставленной ExpandoObject
.
В двух ссылках, упомянутых ниже, очень ясно, что с помощью 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;
}
}
}
Что было бы хорошим местом, чтобы узнать больше об этом? Не API, а почему API? например Почему ExpandoObject не получается из DynamicObject, который ищет базовый тип defacto для программирования на основе метода ruby's method_missing. – Gishu
Не могли бы вы добавить примеры использования, где это возможно? Например, как я могу использовать DynamicObject и какие преимущества? –
Отличные ответы без примеров, подобных этому, похожи на торт без крема на вершине. –