답변:
dynamic
키워드는 런타임에 바인딩해야 변수를 선언하는 데 사용됩니다.
실제 또는 상상 유형에 대해 늦은 바인딩을 사용하려면 dynamic
키워드 를 사용 하고 나머지는 컴파일러에서 수행합니다.
dynamic
키워드를 사용하여 일반 인스턴스와 상호 작용할 때 DLR 은 인스턴스의 일반 메서드에 대한 지연 호출을 수행합니다.
IDynamicMetaObjectProvider
인터페이스는 클래스가 런타임에 바인딩 된 행동을 제어 할 수 있습니다. 키워드를
사용하여 구현 dynamic
과 상호 작용 IDynamicMetaObjectProvider
하면 DLR이 IDynamicMetaObjectProvider
메소드를 호출 하고 객체 자체가 수행 할 작업을 결정합니다.
ExpandoObject
및 DynamicObject
클래스의 구현입니다 IDynamicMetaObjectProvider
.
ExpandoObject
인스턴스에 멤버를 추가하고 dynamic
동맹을 사용할 수있는 간단한 클래스입니다 .
DynamicObject
사용자 정의 된 동작을 쉽게 제공하기 위해 상속 될 수있는 고급 구현입니다.
나는이 질문에 더 명확한 답을 제공하고 역학 ExpandoObject
과 의 차이점이 무엇인지 명확하게 설명하려고 노력할 것이다 DynamicObject
.
매우 빨리 dynamic
키워드입니다. 그 자체로는 유형이 아닙니다. 컴파일러가 디자인 타임에 정적 유형 검사를 무시하고 대신 런타임에 후기 바인딩을 사용하도록 지시하는 키워드입니다. 따라서 우리는 dynamic
이 답변의 나머지 부분에서 많은 시간을 할애하지 않을 것 입니다.
ExpandoObject
그리고 DynamicObject
실제로 유형입니다. SURFACE에서는 서로 매우 유사하게 보입니다. 두 클래스 모두 구현 IDynamicMetaObjectProvider
합니다. 그러나 더 깊이 파고 들면 전혀 비슷하지 않다는 것을 알 수 있습니다.
DynamicObject는 IDynamicMetaObjectProvider
순전히 부분적인 구현으로 개발자가 사용자 지정 기본 저장소 및 검색 동작으로 동적 디스패치를 지원하는 동적 사용자 지정 유형을 구현하여 동적 디스패치 작업을 시작하기위한 출발점입니다.
요컨대, DLR과 함께 사용할 수 있고 원하는 CUSTOM 동작과 함께 사용할 수있는 OWN 형식을 만들려면 DynamicObject를 사용하십시오.
예 : 존재하지 않는 멤버 (예 : 런타임에 추가되지 않은)에 대해 가져 오기를 시도 할 때마다 사용자 정의 기본값을 리턴하는 동적 유형을 원한다고 가정하십시오. 그리고 그 기본값은 "죄송합니다.이 병에는 쿠키가 없습니다!"라고 말합니다. 이와 같이 동작하는 동적 객체를 원하면 필드를 찾을 수 없을 때 발생하는 동작을 제어해야합니다. 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입니다.
DynamicObject
: 재정의 TryGetMember
할 때 false를 반환하면 RuntimeBinderException
존재하지 않는 속성에 액세스하려고 할 때 a 가 throw됩니다. 스 니펫이 실제로 작동하려면를 반환해야합니다 true
.
C # 언어 사양에 따르면 dynamic
형식 선언이 있습니다. 즉 dynamic x
변수 x
에 유형이 있음을 의미합니다 dynamic
.
DynamicObject
은 구현하기 쉽고 IDynamicMetaObjectProvider
형식에 대한 특정 바인딩 동작을 재정의하는 형식입니다.
ExpandoObject
속성 백처럼 작동하는 유형입니다. 즉, 런타임에이 유형의 동적 인스턴스에 속성, 메서드 등을 추가 할 수 있습니다.
dynamic
실제 유형이 아닙니다 ... 컴파일러 에게이 변수에 늦은 바인딩을 사용하도록 지시하는 힌트 일뿐입니다. dynamic
변수는 실제로 object
MSIL에서 와 같이 선언됩니다
위의 예제는 DynamicObject
기본적으로 이미 제공 한 기능을 구현하고 있기 때문에 차이점을 명확하게 나타내지 않습니다 ExpandoObject
.
아래 언급 된 두 링크에서의 도움으로 DynamicObject
실제 유형 ( XElement
아래 링크에서 사용 된 예에서) 을 보존 / 변경하고 속성 및 메소드를보다 잘 제어 할 수 있음이 매우 분명합니다 .
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;
}
}
}