2011-12-06 4 views
3

DynamicObject의 설명서에는 사전을 속성이있는 클래스 인 것처럼 작업 할 수있는 DynamicDictionary의 예가 있습니다.개체 이니셜 라이저를 지원하는 사용자 지정 DynamicObject 클래스를 작성하는 방법

public class Test 
{ 
    public Test() 
    { 
     var result = Enumerable.Range(1, 5).Select(i => new DynamicDictionary 
     { 
      Id = i, 
      Foo = "Foo", 
      Bar = 2 
     }); 
    } 
} 

: 다음 작업을 수행 할 수 있도록, 내가하고 싶은 무엇

public class DynamicDictionary : DynamicObject 
{ 
    Dictionary<string, object> _dictionary = new Dictionary<string, object>(); 

    public int Count 
    { 
     get { return _dictionary.Count; } 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     string name = binder.Name.ToLower(); 
     return _dictionary.TryGetValue(name, out result); 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     _dictionary[binder.Name.ToLower()] = value; 
     return true; 
    } 
} 

클래스를 수정할 수 있습니다 : 여기

는 (간결함을 위해 약간 수정)하는 클래스입니다 질문

  1. 이것은 가능합니까?
  2. 그렇다면 어떻게됩니까?
+0

개체 초기화 도구가 동적 개체와 작동하지 않습니다. – Magnus

+0

기술적으로 @Magnus는 동적 개체에서만 작동하지만 비 동적 방법으로 만 작업 할 수 있습니다. 따라서 동적 객체가 동적이지 않은'Id' 속성을 가지고 있다면 객체 초기화 도구를 사용할 수 있습니다. 하지만이 질문에 대답하는 데 도움이되지 않습니다. – svick

+0

"정상적인"속성의 경우 true, 제대로 작동합니다. 나는 당신이'IEnumerable >'를 취하는 생성자를 추가하고 그것을 사용하여 사전을 생성하는 콜라드를 추측한다. – Magnus

답변

0

Linq의 내장형 ToDictionary() 메서드를 사용하여 문제를 해결할 수있었습니다.

예 :

public Test() 
{ 
    var data = Enumerable.Range(1, 5).Select(i => new 
    { 
     Id = i, 
     Foo = "Foo", 
     Bar = 2 
    }); 
    var result = data 
     .Select(d => d.GetType().GetProperties() 
      .Select(p => new { Name = p.Name, Value = p.GetValue(pd, null) }) 
      .ToDictionary(
       pair => pair.Name, 
       pair => pair.Value == null ? string.Empty : pair.Value.ToString())); 
} 
4

DynamicObjectTryCreateInstance()을 제공합니다. 이는 위와 같은 상황을 의미하지만 C#에서는 사용할 수 없습니다.

나는이 문제를 몇 가지 방법을 참조하십시오

  1. 동적 공장 클래스를 만듭니다. 당신의 이름 argumets과의 Create() 메서드를 호출 할 때, 그것은 사전에 전달 :

    class DynamicDictionaryFactory : DynamicObject 
    { 
        public override bool TryInvokeMember(
         InvokeMemberBinder binder, object[] args, out object result) 
        { 
         if (binder.Name == "Create") 
         { 
          // use binder.CallInfo.ArgumentNames and args 
          // to create the dynamic dictionary 
          result = …; 
          return true; 
         } 
    
         return base.TryInvokeMember(binder, args, out result); 
        } 
    } 
    
    … 
    
    dynamic factory = new DynamicDictionaryFactory(); 
    
    dynamic dict = factory.Create(Id: 42); 
    
  2. 사용 비 동적 컬렉션 이니셜 라이저. 이 코드에서 문자열로 속성 이름을 가진 의미

    아마
    // has to implement IEnumerable, so that collection initializer works 
    class DynamicDictionary 
        : DynamicObject, IEnumerable<KeyValuePair<string, object>> 
    { 
        public void Add(string name, object value) 
        { 
         m_dictionary.Add(name, value); 
        } 
    
        // IEnumerable implmentation and actual DynamicDictionary code here 
    } 
    
    … 
    
    dynamic dict = new DynamicDictionary { { "Id", 42 } }; 
    
  3. 중첩 개체 이니셜 라이저를 사용하는 것입니다 당신이 무엇을 요구에 가장 가까운.

    class DynamicDictionary : DynamicObject 
    { 
        private readonly IDictionary<string, object> m_expandoObject = 
         new ExpandoObject(); 
    
        public dynamic Values 
        { 
         get { return m_expandoObject; } 
        } 
    
        // DynamicDictionary implementation that uses m_expandoObject here 
    } 
    
    … 
    
    dynamic dict = new DynamicDictionary { Values = { Id = 42 } }; 
    
1

(nuget 통해) 오픈 소스 ImpromptuInterface 사용 그것이 Builder Syntax을 갖는다 : 즉, 클래스는 그 속성 객체 이니셜을 사용하여 설정 될 수 dynamic 속성 (예를 들어, Values)을 가질 것이다. 초기화 구문에 가까운 것을 할 수 있습니다. 특히 ImpromptuInterface.Dynamic을 포함 후에는

var result = Enumerable.Range(1, 5).Select(i => Build<DynamicDictionary>.NewObject 
    (
     Id: i, 
     Foo: "Foo", 
     Bar: 2 
    )); 

당신이 <DynamicDictionary> 그것은 본질적으로 같은 것 인 ImpromptuDictionary를 사용 놓으면 너무 그 구문 페이지에있는 다른 옵션이 있습니다 할 수 있습니다. 그리고 빌드 구문에 대해서도 source을 볼 수 있습니다.

0

이 같은 임베디드 언어의 패턴을 볼 때, 내가 확장 방법을 사용하는 경향이있다, 그래서 나는 나의 목표를 달성하기 위해 다음과 같은 코드를 작성할 수 :

public Test() 
{ 
    var data = Enumerable.Range(1, 5).Select(i => new 
    { 
     Id = i, 
     Foo = "Foo", 
     Bar = 2 
    }.AsDynamicDictionary()); 
} 

을 그런 다음 임의의 object (익명 형식의 문자 포함)을 DynamicDictionary으로 변환하는 코드로 확장 메소드를 정의합니다.

public static class DynamicDictionaryExtensions 
{ 
    public static DynamicDictionary AsDynamicDictionary(this object data) 
    { 
     if (data == null) throw new ArgumentNullException("data"); 
     return new DynamicDictionary(
       data.GetType().GetProperties() 
       .Where(p => p. && p.CanRead) 
       .Select(p => new {Name: p.Name, Value: p.GetValue(data, null)}) 
       .ToDictionary(p => p.Name, p => p.Value) 
     ); 
    } 
} 

IDictionary<string, object>을 받으려면 DynamicDictionary에 생성자를 구현해야하지만 이는 케이크 조각입니다.

+0

'p => p. && p.CanRead' 여기에 뭔가 빠져있는 것처럼 보입니다. – svick

관련 문제