2010-06-13 1 views
40

dynamic C# 4.0 개체의 속성을 런타임에만 알려진 속성 이름으로 수정하는 방법을 찾고 있습니다.다른 변수에 이름이있을 때 C# 4 동적 개체의 속성을 설정하는 방법

string key = "TestKey"; 
dynamic e = new ExpandoObject(); 
e[key] = "value"; 

에 해당하는 것 :

dynamic e = new ExpandoObject(); 
e.TestKey = "value"; 

같은 것을 할 수있는 방법이 있나요 (ExpandoObject 그냥 예제로 사용이,이 IDynamicMetaObjectProvider를 구현하는 모든 클래스가 될 수 있음)

아니면 앞으로 반사하는 유일한 방법입니까?

+0

속성은 해시 맵에 속성을 넣어 런타임에서 확인할 수있는 경우가 아니면 자신의 솔루션 일 수 있습니다. –

+0

가능한 [ExpandoObject에 알 수없는 (디자인 타임에) 속성 추가] (http://stackoverflow.com/questions/2974008/adding-unknown-at-design-time-properties-to-an-expandoobject) – nawfal

답변

16

매우 쉽게 아니요. 이 아닌 dynamic이 아닌 일반 유형 모델을 가정하므로 반사가 작동하지 않습니다. 실제로 그냥 일반 물체와 대화하는 중이라면 여기에서 반사를 사용하십시오. 그렇지 않으면 컴파일러에서 기본 할당을 위해 생성하는 코드를 리버스 엔지니어링하여 유연하게 멤버 이름을 갖도록 조정할 수 있습니다. 솔직히 말해서, 이것은 매력적인 옵션이 아닙니다. 간단한 :

dynamic foo = ... 
foo.Bar = "abc"; 

는로 변환 :

if (<Main>o__SiteContainer0.<>p__Site1 == null) 
{ 
    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Bar", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) })); 
} 
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, foo, "abc"); 

당신은 동적 및 비 동적 객체 모두를 위해 작동하는 방식하려면 다음 FastMember이 편리하고, 중 하나에서 일을 유형 또는 객체 수준 :

// could be static or DLR 
var wrapped = ObjectAccessor.Create(obj); 
string propName = // something known only at runtime 
Console.WriteLine(wrapped[propName]); 

누메트에서 사용할 수 있으며 동적 및 비 동적 sc enarios.

+0

감사 Marc - 나는 명백한 것 그러나 분명히없는 것을 놓치고 있다고 생각했다! :) 코드 방출을 수행하는 방법에 대한 좋은 예에 대한 링크가 있습니까? 내가 갈 수 있다면 이것은 뭔가 공유하는 것처럼 보입니다! –

+0

@Kieran - 필요한 것에 따라 다릅니다. 그것은 당신이 방출을 필요로하는 것처럼 들리지 않았습니다. (내가 게시 한 코드는 그것이 얼마나 못생긴지의 견본이었습니다). –

+0

ExpandoObject가 사전을 백업 저장소로 사용하고 OP가 원래 제안한대로 정확하게 사용될 수 있음을 설명하지 않았으므로 Downvoted. expandoObject에 반사 또는 방출 할 필요가 없습니다. @MarcGravell은 비 확장 객체 (동적 var에 할당 된 일반 객체는 물론)에 대해서는 깨끗한 해결책이 없다는 사실이 옳다. –

3

내 오픈 소스 프레임 워크 Dynamitey에는 DLR을 사용하여 문자열 이름을 기반으로 호출 할 수있는 메소드가 있습니다. 바인딩 사이트 캐싱 작업을 수행하고 하나의 메서드 호출로이를 간소화합니다. 또한 동적이지 않은 오브젝트에 대한 리플렉션보다 빠릅니다.

Dynamic.InvokeSet(e, "TestKey", "value"); 
50

폴 Sasik 법안에 맞게 수 C# 4.0 Dynamic vs Expando... where do they fit?

using System; 
using System.Dynamic; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic expando = new ExpandoObject(); 
     var p = expando as IDictionary<String, object>; 
     p["A"] = "New val 1"; 
     p["B"] = "New val 2"; 

     Console.WriteLine(expando.A); 
     Console.WriteLine(expando.B); 
    } 
} 
0

fast-member에 비슷한 질문에 대답 - 그것은 즉석에서 IL를 생성하는 것처럼 보이지만, 그렇게는 처음 사용 후 정말 빨리 캐시 .

6

Jonas의 답변에 추가하려면 새 var p를 만들 필요가 없습니다. 대신이 접근법을 사용하십시오 :

using System; 
using System.Dynamic; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic expando = new ExpandoObject(); 
     ((IDictionary<String, object>)expando)["A"] = "New val 1"; 
     ((IDictionary<String, object>)expando)["B"] = "New val 2"; 

     Console.WriteLine(expando.A); 
     Console.WriteLine(expando.B); 
    } 
} 
관련 문제