동적 객체의 멤버를 어떻게 반영합니까?


131

.NET 4의 dynamic 키워드로 선언 된 객체에서 속성 사전과 값을 가져와야합니까? 이것은 반사를 사용하여 작동하지 않는 것 같습니다.

예:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???

답변:


32

IDynamicMetaObjectProvider가 동적 멤버 이름을 제공 할 수있는 경우이를 가져올 수 있습니다. 참조 은 getMemberNames의 아파치에서 구현 PCL 라이브러리 라이센스 Dynamitey을 (nuget에서 찾을 수있는), 그것은 작동 ExpandoObject들과 DynamicObject그 구현이야 GetDynamicMemberNames및 기타 IDynamicMetaObjectProvider의 구현과 메타 오브젝트를 제공하는 사람 GetDynamicMemberNames정의가 이상을 테스트하지 않고 is IDynamicMetaObjectProvider.

멤버 이름을 얻은 후에는 올바른 방법으로 값을 얻는 것이 약간 더 효과적이지만 Impromptu는이 작업을 수행하지만 흥미로운 부분을 지적하고 이해하기가 더 어렵습니다. 여기 문서가 있으며 리플렉션보다 빠르거나 빠르지 만 expando의 사전 조회보다 빠를 것 같지는 않지만 모든 객체, expando, dynamic 또는 original에서 작동합니다.


17
포인트에 도달하여 코드는 다음과 같습니다. var tTarget = target as IDynamicMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDynamicMemberNames ()); }
Flatliner DOA

훌륭한 도서관 주셔서 감사합니다. 이 라이브러리 dynamicjson.codeplex.com에 동적 객체를 라운드 트리핑하는 데 문제 가 있었고 라이브러리로 확장 할 수있었습니다.
JJS

1
예를 들어주세요.
Demodave

105

ExpandoObject의 경우 ExpandoObject 클래스는 실제로 IDictionary<string, object>해당 속성을 구현 하므로 솔루션은 캐스팅만큼 간단합니다.

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

일반 동적 객체에는 작동하지 않습니다. 이 경우 IDynamicMetaObjectProvider를 통해 DLR로 드롭 다운해야합니다.


고마워, 불행히도 샘플은 약간 단순화되었습니다. 실제 유형이 무엇인지 모른 채 동적 객체를 검사 할 수 있어야합니다.
Flatliner DOA

2
이것은 ExpandoObject 클래스의 객체에서만 작동합니다. DynamicObject 클래스는 IDictionary를 구현하지 않고 IDynamicMetaObjectProvider를 구현하는 또 다른 확장 가능한 클래스입니다.
Sharique Abdullah

1
그러나 OP의 질문에 대답합니다.
Sharique Abdullah

58

고려해야 할 몇 가지 시나리오가 있습니다. 우선, 객체의 유형을 확인해야합니다. 이를 위해 간단히 GetType ()을 호출 할 수 있습니다. 유형이 IDynamicMetaObjectProvider를 구현하지 않으면 다른 객체와 동일한 리플렉션을 사용할 수 있습니다. 다음과 같은 것 :

var propertyInfo = test.GetType().GetProperties();

그러나 IDynamicMetaObjectProvider 구현의 경우 단순 리플렉션이 작동하지 않습니다. 기본적으로이 객체에 대해 더 알아야합니다. 그것이 ExpandoObject (IDynamicMetaObjectProvider 구현 중 하나) 인 경우 itowlson이 제공 한 답변을 사용할 수 있습니다. ExpandoObject는 속성을 사전에 저장하고 동적 객체를 사전에 캐스트 할 수 있습니다.

DynamicObject (다른 IDynamicMetaObjectProvider 구현) 인 경우이 DynamicObject가 노출하는 모든 방법을 사용해야합니다. DynamicObject는 실제로 속성 목록을 어디에나 "저장"할 필요가 없습니다. 예를 들어 다음과 같은 작업을 수행 할 수 있습니다 ( 블로그 게시물 의 예를 재사용하고 있음 ).

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

이 경우 지정된 이름으로 속성에 액세스하려고 할 때마다 개체는 속성 이름을 문자열로 반환합니다.

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

따라서 반영 할 항목이 없습니다.이 개체에는 속성이 없으며 동시에 모든 유효한 속성 이름이 작동합니다.

IDynamicMetaObjectProvider 구현의 경우 ExpandoObject와 같은 속성 목록을 가져오고 나머지 부분은 무시하거나 예외를 throw 할 수있는 알려진 구현을 필터링해야합니다.


7
내가 소비하는 유형이 동적 인 경우 기본 유형에 대한 가정을해서는 안됩니다. 멤버 목록을 얻기 위해 GetDynamicMemberNames를 호출 할 수 있어야합니다. 정적 유형은 동적 유형보다 런타임 검사 지원 기능이 더 뛰어납니다.
Flatliner DOA

2
동적 개체에 대한 GetDynamicMemberNames () 메서드를 재정 의하여 동적 멤버의 목록 이름을 반환 할 수 있습니다. 문제는 모든 동적 객체 가이 메소드를 가지고 있다고 보장하지는 않는다는 것입니다 (ExpandoObject는 그렇지 않습니다). 정적 유형에 대해 리플렉션이 더 잘 작동한다는 것은 놀라운 일이 아닙니다. 처음부터 그들을 위해 만들어졌습니다. 역학에서는 단위 테스트 및 TDD에 더 의존해야합니다.
Alexandra Rusina

1
GetDynamicMemberNames에 대한 MSDN 문서 ()는 언급한다 : "이 방법은 디버깅 목적으로 만 존재한다."정말 기운이 없습니다 :(
NicoJuicy

19

Newtonsoft Json.Net 필요

조금 늦었지만 나는 이것을 생각해 냈습니다. 그것은 단지 당신에게 키를 제공하고 당신은 역동적 인 것들을 사용할 수 있습니다 :

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

그런 다음 간단히 다음과 같이 가르칩니다.

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

값을 문자열 또는 다른 객체로 가져 오거나 다른 동적 작업을 수행하고 조회를 다시 사용하도록 선택합니다.


당신은 반환 목록이 필요하지 않습니다.
aloisdg codidact.com으로 이전

4
완전한! JObject 속성을 변경해야했습니다 .AsJObject = dynamicToGetPropertiesFor; 객체 속성에 AsJObject = (JObject) JToken.FromObject (obj); 그러나!!
k25

@ k25가 말한 것을 반복하십시오. JObject attributesAsJObject = dynamicToGetPropertiesFor;다음과 같이 바꿔야 var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);합니다. 이 시점에서 다음과 같은 작업을 수행하여 속성 이름과 값의 사전을 얻을 수 있습니다 var objProperties = jObject.ToObject<Dictionary<string, object>>();. 손에 들고, 당신은 경주에서 벗어납니다. 역 동성이 필요하지 않습니다. 이 서브 클래스의 아무것도 함께 잘 작동DynamicObject
Flydog57
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.