ExpandoObject의 진정한 이점은 무엇입니까?


587

ExpandoObject의 클래스는 런타임시 객체에 .NET 4 임의로 설정 속성 수에 추가.

Dictionary<string, object>, 또는 심지어 해시 테이블 을 사용하는 것보다 이점이 있습니까? 내가 알 수있는 한, 이것은 약간 더 간결한 구문으로 액세스 할 수있는 해시 테이블에 지나지 않습니다.

예를 들어, 왜 이럴까요 :

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를 사용하면 얻을 수있는 실제 이점은 무엇입니까?

답변:


689

언급 한 MSDN 기사를 작성 했으므로이 기사에 대답해야한다고 생각합니다.

먼저이 질문을 예상했기 때문에 ExpandoObject : Dynamic in C # 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;

       e?.Invoke(d, new EventArgs());
   }

   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);
   }
}

또한 동적으로 이벤트 인수를 허용하는 데 방해가되는 것은 없습니다. 즉,을 사용하는 대신 핸들러의 두 번째 인수를 EventHandler사용 EventHandler<dynamic>하는을 사용할 수 있습니다 dynamic.


53
흥미 롭군 info re : events 주셔서 감사합니다. 저에게는 새로운 것이 었습니다.
Reed Copsey

16
@AlexandraRusina, 당신이 말할 때 이벤트인지 어떻게 알 수 d.MyEvent = null;있습니까?
Shimmy Weitzhandler

20
어쩌면 내가 누락 된 것이지만 이것은 이벤트가 아닙니다-이것은 대리자 유형의 간단한 속성입니다.
Sergey Berezovskiy

7
첫 번째 블록은 익명 유형을 사용하여 작성할 수 있습니다 var expando = new { Address = new { State = "WA" } }; Console.WriteLine(expando.Address.State);. 그리고 정적으로 입력되면이 문맥에서 더 유용합니다.
nawfal

13
@nawfal은 옳지 않습니다. 익명은 Expando와 다릅니다. 익명 유형을 작성 중이므로 임의의 특성을 추가 할 수 없습니다.
Dr Blowhard

75

하나의 장점은 바인딩 시나리오에 대한 것입니다. 데이터 그리드 및 속성 그리드는 TypeDescriptor 시스템을 통해 동적 속성을 선택합니다. 또한 WPF 데이터 바인딩은 동적 속성을 이해하므로 WPF 컨트롤은 사전보다 ExpandoObject에 더 쉽게 바인딩 할 수 있습니다.

일부 시나리오에서는 사전 항목이 아닌 DLR 속성이 필요한 동적 언어와의 상호 운용성이 고려 될 수도 있습니다.


6
동적 객체에 그 데이터 바인딩이 깨진 것 같다 . 보고 사용자 eisenbergeffect는 여기 caliburn.micro의 조정자입니다. @AlexandraRusina 당신은 "해결되지 않습니다"버그 및 상태의 상태에 댓글을 달 수
surfmuggle

2
그 호기심, 나는 현재에 바인딩 할 수 있어요 List<dynamic>IEnumerable<dynamic>사용 WPF4
그레이엄베이스

47

저에게있어 실질적인 이점은 XAML에서 완전히 손쉬운 데이터 바인딩입니다.

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

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

28

다른 언어와의 상호 운용성에 대해 DLR생각할 수 있습니다. 당신은 그들에게 전달할 수 없습니다 Dictionary<string, object>그것이 아니다로 IDynamicMetaObjectProvider. 또 다른 이점은 INotifyPropertyChangedWPF의 데이터 바인딩 세계에서 구현할 수 있다는 것 외에 다른 이점도 제공한다는 Dictionary<K,V>것입니다.


19

프로그래머 편의성에 관한 것입니다. 이 객체로 빠르고 더러운 프로그램을 작성하는 것을 상상할 수 있습니다.


9
@제이. 헨드릭스는 그가 "더러운"이라고 말한 것을 잊지 마십시오. Intellisense는 단점이 있지만 디버그 및 버그 잡기가 더 쉽습니다. 나는 이상한 (그리고 항상 드문) 경우를 다루지 않는 한 동적 유형보다 정적을 선호합니다.
Phil

편의를 위해 +1 그러나 익명 유형은 간단한 속성 백처럼 똑같이 편리 할 수 ​​있으며 정적에 더 좋습니다.
nawfal

1
프로덕션 코드에서 사용하고 싶지 않지만 테스트 코드에서 매우 편리하며 매우 아름답게 보일 수 있습니다.
Tobias

14

더 이상 사전을 사용하여 동적으로 추가 된 속성을 "가짜"로 만들지 않기 때문에 구문상의 이점이 있다고 생각합니다.

그것은 내가 생각하는 동적 언어와 상호 작용합니다.


11

들어오는 구조화 된 데이터 (예 : XML, Json)에 대한 동적 임시 유형을 만들기 위해 ExpandoObject 를 사용하는 방법 에 대한 훌륭한 MSDN 기사 의 예입니다 .

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 클래스함께 함수 프로그래밍의 일부 요소를 C # 코드에 도입 할 수 있습니다. JavaScript 또는 PHP와 같이 동적 언어에서 알고 있습니다.


4

이것이 편리한 경우가 있습니다. 예를 들어 Modularized shell에 사용하겠습니다. 각 모듈은 자신의 설정에 바인딩 된 자체 구성 대화 상자를 정의합니다. Datacontext이므로 ExpandoObject를 제공하고 구성 저장소에 값을 저장합니다. 이 방법으로 구성 대화 상자 작성기는 값에 바인딩하기 만하면 자동으로 작성되고 저장됩니다. (그리고 물론 이러한 설정을 사용하기 위해 모듈에 제공)

사전보다 사용하기가 더 쉽습니다. 그러나 모든 사람들은 내부적으로 사전이라는 것을 알고 있어야합니다.

LINQ는 구문 설탕과 비슷하지만 때로는 쉽게 할 수 있습니다.

따라서 귀하의 질문에 직접 답하십시오 : 더 쓰고 쉽게 읽을 수 있습니다. 그러나 기술적으로는 본질적으로 Dictionary<string,object>(값을 나열하기 위해 하나로 캐스트 할 수도 있습니다).


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

모든 것이 ToString ()을 가지고 있기 때문에 작동한다고 생각합니다. 그렇지 않으면 유형을 알고 '객체'를 해당 유형으로 캐스팅해야합니다.


이 중 일부는 다른 것보다 더 자주 유용합니다. 철저하게 노력하고 있습니다.

  1. 보다 직접적인 점 표기법을 사용하여 컬렉션에 액세스하는 것이 훨씬 더 자연 스러울 수 있습니다.이 경우 효과적으로 "사전"입니다.

  2. 마치 이것이 정말 좋은 Tuple로 사용될 수있는 것처럼 보입니다. 여전히 멤버를 "Item1", "Item2"등으로 호출 할 수 있지만 이제는 Tuple과 달리 변경할 수 없습니다. 이것은 지적 지원이 부족하다는 큰 단점이 있습니다.

  3. 사전에 대한 느낌과 마찬가지로 "멤버 이름을 문자열로"사용하는 것이 불편할 수 있으며, "문자열을 실행하는 것"과 같은 느낌이들 수 있으며 명명 규칙이 코드화되고 형태소 작업 및 코드가 멤버를 사용하는 방법을 이해하려고 할 때 음절 :-P

  4. ExpandoObject 자체 또는 멤버에 값을 할당 할 수 있습니까? 다이나믹 / 다이내믹 []과 비교 및 ​​대조하고 필요에 가장 적합한 것을 사용하십시오.

  5. 동적 / 동적 []이 foreach 루프에서 작동한다고 생각하지 않습니다. var를 사용해야하지만 ExpandoObject를 사용할 수도 있습니다.

  6. 클래스에서 동적으로 데이터 멤버로 사용할 수는 없습니다. 아마도 키워드와 비슷하기 때문에 ExpandoObject를 사용하면 좋을 것입니다.

  7. 나는 그것이 "ExpanoObject"일 것으로 기대하고있다. 매우 일반적인 것들을 구별하는 데 유용 할 것이다.


여러 레벨을 한 번에 드릴 다운 할 수 있으면 좋을 것입니다.

var e = new ExpandoObject();
e.position.x = 5;
etc...

그것이 가장 좋은 예는 아니며, 자신의 프로젝트에서 적절하게 우아한 사용법을 상상하십시오.

코드로 이들 중 일부를 빌드하고 결과를 인텔리전스하게 전달할 수 없다는 것은 부끄러운 일입니다. 그래도 어떻게 작동하는지 잘 모르겠습니다.

그들이 회원뿐만 아니라 가치를 가질 수 있다면 좋을 것입니다.

var fifteen = new ExpandoObject();
fifteen = 15;
fifteen.tens = 1;
fifteen.units = 5;
fifteen.ToString() = "fifteen";
etc...

-3

valueTuples 이후에 ExpandoObject 클래스를 사용하는 것은 무엇입니까? ExpandoObject가있는이 6 줄 코드 :

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));

튜플 구문 외에도 강력한 유형 유추 및 강력한 지원


1
값 튜플을 사용하면 Tc = 5를 쓸 수 없다는 점에서 예제가 동일하지 않습니다. T를 정의한 후에는 ExpandoObject를 사용하면 동적이기 때문에이를 수행 할 수 있습니다. 튜플 값이있는 예제는 익명 유형을 선언하는 것과 매우 동일합니다. 예 : var T2 = new {x = 1, y = 2, z = new {a = 3, b = 4}};
LxL

정의하지 않고 Tc = 5를 작성해야하는 이유는 무엇입니까? ExpandoObject는 .net에 속하지 않는 COM 개체를 처리 할 때만 유용합니다. 그렇지 않으면 디자인 시간과 런타임 모두에서 더럽고 버그가 있기 때문에이 ExpandoObject를 사용하지 마십시오.
영어. M.Hamdy

1
z에 처음에 (a : 3, b : 4)를 할당 한 다음 z에 추가 c 속성을 지정하고 싶습니까? 가치있는 튜플로 할 수 있습니까?
LxL

따라서 요점은 ExpandoObject와 다른 용도로 설계된 튜플을 비교할 수 없다는 것입니다. 방법을 비교하여 ExpandoObject의 기능인 동적 구조를 무시했습니다.
LxL
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.