ExpandoObject, DynamicObject 및 dynamic의 차이점


170

무슨 사이의 차이점은 System.Dynamic.ExpandoObject, System.Dynamic.DynamicObject그리고 dynamic?

어떤 상황에서 이러한 유형을 사용합니까?

답변:


154

dynamic키워드는 런타임에 바인딩해야 변수를 선언하는 데 사용됩니다.
실제 또는 상상 유형에 대해 늦은 바인딩을 사용하려면 dynamic키워드 를 사용 하고 나머지는 컴파일러에서 수행합니다.

dynamic키워드를 사용하여 일반 인스턴스와 상호 작용할 때 DLR 은 인스턴스의 일반 메서드에 대한 지연 호출을 수행합니다.

IDynamicMetaObjectProvider인터페이스는 클래스가 런타임에 바인딩 된 행동을 제어 할 수 있습니다. 키워드를
사용하여 구현 dynamic과 상호 작용 IDynamicMetaObjectProvider하면 DLR이 IDynamicMetaObjectProvider메소드를 호출 하고 객체 자체가 수행 할 작업을 결정합니다.

ExpandoObjectDynamicObject클래스의 구현입니다 IDynamicMetaObjectProvider.

ExpandoObject인스턴스에 멤버를 추가하고 dynamic동맹을 사용할 수있는 간단한 클래스입니다 .
DynamicObject사용자 정의 된 동작을 쉽게 제공하기 위해 상속 될 수있는 고급 구현입니다.


2
이것에 대해 더 배우기 좋은 곳은 무엇입니까? API가 아니라 API의 이유는 무엇입니까? 예. 왜 ExpandoObject가 DynamicObject에서 파생되지 않는가? 루비의 'method_missing'기반 프로그래밍에 대한 사실상의 기본 유형을 찾는다.
기슈

4
가능한 경우 사용 예를 추가 할 수 있습니까? 예를 들어 DynamicObject를 어떻게 사용하고 어떤 이점이 있습니까?
oɔɯǝɹ

10
이와 같은 예가없는 훌륭한 답변은 크림이없는 케이크와 같습니다.
Teoman shipahi


68

나는이 질문에 더 명확한 답을 제공하고 역학 ExpandoObject과 의 차이점이 무엇인지 명확하게 설명하려고 노력할 것이다 DynamicObject.

매우 빨리 dynamic키워드입니다. 그 자체로는 유형이 아닙니다. 컴파일러가 디자인 타임에 정적 유형 검사를 무시하고 대신 런타임에 후기 바인딩을 사용하도록 지시하는 키워드입니다. 따라서 우리는 dynamic이 답변의 나머지 부분에서 많은 시간을 할애하지 않을 것 입니다.

ExpandoObject그리고 DynamicObject실제로 유형입니다. SURFACE에서는 서로 매우 유사하게 보입니다. 두 클래스 모두 구현 IDynamicMetaObjectProvider합니다. 그러나 더 깊이 파고 들면 전혀 비슷하지 않다는 것을 알 수 있습니다.

DynamicObject는 IDynamicMetaObjectProvider순전히 부분적인 구현으로 개발자가 사용자 지정 기본 저장소 및 검색 동작으로 동적 디스패치를 ​​지원하는 동적 사용자 지정 유형을 구현하여 동적 디스패치 작업을 시작하기위한 출발점입니다.

  1. DynamicObject는 직접 생성 할 수 없습니다.
  2. 개발자로서 귀하가 사용할 수 있도록 DynamicObject를 확장해야합니다.
  3. DynamicObject를 확장하면 이제 동적 디스패치가 런타임시 기본 데이터 표현에 내부적으로 저장된 데이터로 해석되는 방법에 관한 CUSTOM 동작을 제공 할 수 있습니다.
  4. ExpandoObject는 기본 데이터를 사전 등에 저장합니다. DynamicObject를 구현하면 원하는 위치에 데이터를 저장할 수 있습니다. (예 : 발송시 데이터를 가져오고 설정하는 방법은 전적으로 귀하에게 달려 있습니다).

요컨대, 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!")

ExpandoObjectIDynamicMetaObjectProvider.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입니다.

위의 많은 예제 소스가 기반으로하는 유용한 튜토리얼.


아주 좋은 설명입니다. 기술 수정 하나만 : ExpandoObject는 DynamicObject에서 상속되지 않습니다.
Mike Rosoft

에 대한 예제에서 약간의 수정 DynamicObject: 재정의 TryGetMember할 때 false를 반환하면 RuntimeBinderException존재하지 않는 속성에 액세스하려고 할 때 a 가 throw됩니다. 스 니펫이 실제로 작동하려면를 반환해야합니다 true.
lluchmk

36

C # 언어 사양에 따르면 dynamic형식 선언이 있습니다. 즉 dynamic x변수 x에 유형이 있음을 의미합니다 dynamic.

DynamicObject은 구현하기 쉽고 IDynamicMetaObjectProvider형식에 대한 특정 바인딩 동작을 재정의하는 형식입니다.

ExpandoObject속성 백처럼 작동하는 유형입니다. 즉, 런타임에이 유형의 동적 인스턴스에 속성, 메서드 등을 추가 할 수 있습니다.


25
dynamic실제 유형이 아닙니다 ... 컴파일러 에게이 변수에 늦은 바인딩을 사용하도록 지시하는 힌트 일뿐입니다. dynamic변수는 실제로 objectMSIL에서 와 같이 선언됩니다
Thomas Levesque

1
@Thomas : 컴파일러의 관점에서 볼 때 유형이지만 런타임 표현은 Object의 표현입니다. 여러 MS 프레젠테이션에서 "정적으로 동적으로 입력 된"문을 찾을 수 있습니다.
Brian Rasmussen

3
@Thomas : 언어 사양에 "C # 4.0은 dynamic이라는 새로운 정적 유형을 도입했습니다"라고 말합니다.
Brian Rasmussen

실제로 ... 그러나 DynamicObject 또는 ExpandoObject와 같은 형식과 상속 관계가 없기 때문에 형식으로 간주하는 것이 혼란 스럽다고 생각합니다.
Thomas Levesque

3
@NathanA 나는 당신과 함께 있습니다. 그러나 언어 사양에서는이를 유형이라고 부릅니다.
Brian Rasmussen

0

위의 예제는 DynamicObject기본적으로 이미 제공 한 기능을 구현하고 있기 때문에 차이점을 명확하게 나타내지 않습니다 ExpandoObject.

아래 언급 된 두 링크에서의 도움으로 DynamicObject실제 유형 ( XElement아래 링크에서 사용 된 예에서) 을 보존 / 변경하고 속성 및 메소드를보다 잘 제어 할 수 있음이 매우 분명합니다 .

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;    
        }    
    }    
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.