문자열을 통해 C # 동적 속성 값 가져 오기


182

dynamic문자열 로 c # 속성 값에 액세스하고 싶습니다 .

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

문자열로 "value2"만있는 경우 d.value2 ( "random") 값을 얻으려면 어떻게해야합니까? 자바 스크립트에서는 d [ "value2"]를 사용하여 값 ( "random")에 액세스 할 수 있지만 C # 및 리플렉션을 사용하여이 작업을 수행하는 방법을 잘 모르겠습니다. 내가 온 가장 가까운 것은 이것입니다 :

d.GetType().GetProperty("value2") ...하지만 실제 가치를 얻는 방법을 모르겠습니다.

언제나 그렇듯이 도움을 주셔서 감사합니다!


26
이것은 "동적"의 의도 된 목적이 아니며이 시나리오는 "객체"보다 "동적"에서 더 잘 작동하지 않습니다. "동적"을 사용하면 컴파일시 속성 이름 을 알 수 있지만 유형 을 알 수없는 경우 속성에 액세스 할 수 있습니다 . 컴파일 타임에 이름이나 유형을 알지 못하므로 dynamic은 도움이되지 않습니다.
Eric Lippert


3
@EricLippert 나는이 질문이 오래되었다는 것을 알고 있지만 누군가가 나중에 볼 수 있도록 의견을 남기려고합니다. 경우에 따라 동적 또는 객체를 사용할지 (예 : JSON 파서를 사용하는 경우) 선택할 수 없으며 문자열 (예 : 구성 파일에서)에서 속성을 가져 오기를 원할 수 있습니다. 처음에는 생각할 수 있습니다.
Pedrom

답변:


217

당신은 일단 당신의 PropertyInfo(에서 GetProperty), 당신은 전화해야 GetValue하고의 가치를 얻을하려는 인스턴스에 전달합니다. 귀하의 경우 :

d.GetType().GetProperty("value2").GetValue(d, null);

4
나는 'd.GetType().GetProperty("value2").GetValue(d)' threw an exception of type 'System.Reflection.TargetInvocationException' dynamic {System.Reflection.TargetInvocationException}그것으로 시계 창에 점점 ..?
TimDog

6
GetValue는 추가 매개 변수가 필요하다고 생각합니다. egdGetType (). GetProperty ( "value2"). GetValue (d, null)
dommer

3
익명 유형이 아닌 진정한 동적 ExpandoObject에서 작동합니까? new {}정의 된 속성으로 실제 익명 형식을 생성하기 때문에 GetType / GetProperty를 호출하는 것은 의미가 있지만 GetType을 호출하면 ExpandoObject의 속성이 있지만 반드시 동적 속성 인 것은 아닌 ExpandoObject의 경우는 어떻습니까?
Triynko

16
-1. 동적으로 캐스트 된 간단한 .NET 오브젝트에서만 작동합니다. 는 Expando 또는 ViewBag이 ASP.NET MVC 사용하는 것처럼 사용자 정의 동적 오브젝트 작동하지 않습니다
필립 Munin

8
이는 Expando 개체와 함께 작동 것입니다 : (((IDictionary <문자열, 개체>) ×)) [ "값 1"]
마이클 Bahig

39
public static object GetProperty(object target, string name)
{
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
    return site.Target(site, target);
}

Microsoft.CSharp에 대한 참조를 추가하십시오. 동적 유형 및 개인 속성 및 필드에도 작동합니다.

편집 :이 방법이 작동하는 동안 Microsoft.VisualBasic.dll 어셈블리 에서 거의 20 배 빠른 방법이 있습니다 .

public static object GetProperty(object target, string name)
{
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}

2
VisualBasic 버전이 원래의 'GetProperty'버전과 동일하지 않다는 것을 언급하고 싶었습니다. GetProperty는 실제로 동적 GetMember를 호출하여 IronPython의 Python 객체에서도 작동합니다.
Trevor Sundberg

대상은 무엇입니까?
Demodave

@Demodave 속성을 호출하려는 객체 ( d질문에서).
IllidanS4는 Monica가

➕1 이것은 FastMember와 HyperDescriptor가 그렇게하지 않을 경우 개인 재산에 적용되었습니다
Chris Marisic

@ IllidanS4 CallSite코드와 CallByName코드를 비교할 때 CallSite인스턴스 를 캐싱하는 동안 두 가지를 비교 했 습니까? 나는 당신의 첫 번째 방법의 비용이 거의 순수의 활성화 의심 것입니다 BinderCallSite아닌 호출Target()
크리스 Marisic

24

Dynamitey 는 오픈 소스 .net std라이브러리이므로 dynamic키워드 처럼 호출 할 수 있지만 컴파일러가 대신 속성 이름에 문자열을 사용하면 속도가 반향됩니다 (거의 빠르지는 않습니다). 동적 키워드를 사용하는 것과 같지만 이는 컴파일러가 정적으로 캐시하는 동적 캐싱의 추가 오버 헤드 때문입니다.

Dynamic.InvokeGet(d,"value2");

11

둘 다를 얻기위한 가장 쉬운 방법 setter과를 getter포함한 모든 유형의 작동하는 속성 dynamicExpandoObject사용하는 것입니다 FastMember또한 (가 방출을 사용하는) 가장 빠른 방법은 주위를 될 일이.

당신이 중 하나 얻을 수있는 TypeAccessor특정 유형 또는에 따라 ObjectAccessor특정 유형의 인스턴스의 기반.

예:

var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");

var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");

dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");

var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");

typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");

typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");

8

동적 객체를 요청할 때 대부분의 경우 ExpandoObject를 얻습니다 (위의 익명이지만 정적으로 유형이 지정된 예제에는 없지만 JavaScript 및 선택한 JSON 파서 JsonFx에 대해서는 ExpandoObjects를 생성합니다).

동적이 실제로 ExpandoObject 인 경우 http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx에 설명 된대로 IDictionary로 캐스팅하여 리플렉션을 피할 수 있습니다 .

IDictionary로 캐스팅하면 .Item 및 .ContainsKey와 같은 유용한 메소드에 액세스 할 수 있습니다.


불행히도, IDictionary로 캐스트하고 예를 들어 TryGetValue를 사용하면 평범한 오래된 객체가 반환됩니다. 이 시점에서 암시 적 연산자는 컴파일시에만 고려되므로 사용할 수 없습니다. 예를 들어, Int64로 암시 적으로 변환 된 Int64Proxy 클래스가 있다면 Int64? i = data.value; //data is ExpandoObject암시 적 연산자를 자동으로 조회하고 호출합니다. 반면에 "값"필드가 존재하는지 테스트하기 위해 IDictionary를 사용해야한다면 Int64에 오류없이 캐스트되지 않는 객체를 다시 얻을 수 있을까요?
Triynko

5

GetProperty / GetValue는 Json 데이터에서 작동하지 않으며 항상 null 예외를 생성하지만 다음 방법을 시도 할 수 있습니다.

JsonConvert를 사용하여 객체를 직렬화하십시오.

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));

그런 다음 문자열에 직접 캐스팅하여 액세스하십시오.

var pn = (string)z["DynamicFieldName"];

Convert.ToString (request) [ "DynamicFieldName"]을 적용해도되지만, 테스트하지는 않았습니다.


2
이 메소드는 다음 오류를 생성합니다. 오류 CS0021 : 'object'유형의 표현식에 []를 사용하여 인덱싱을 적용 할 수 없습니다. new JavaScriptSerializer().Deserialize<object>(json);제안한 방식으로 "속성"을 얻는 데 사용
Kris Kilton

4

d.GetType (). GetProperty ( "value2")

PropertyInfo 객체를 반환합니다.

그럼 해

propertyInfo.GetValue(d)

2
덕분에,이 정답이었다, 그러나 위에서 언급 한 바와 같이 GetValue(d)요구로GetValue(d,null)
TimDog

4

이것은 내가 동적 속성 값을 얻는 방법입니다.

    public dynamic Post(dynamic value)
    {            
        try
        {
            if (value != null)
            {
                var valorCampos = "";

                foreach (Newtonsoft.Json.Linq.JProperty item in value)
                {
                    if (item.Name == "valorCampo")//property name
                        valorCampos = item.Value.ToString();
                }                                           

            }
        }
        catch (Exception ex)
        {

        }


    }

1

.GetType()returns 때 동적 문서에서 속성을 얻으려면 null다음을 시도하십시오.

var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;

0

.Net core 3.1에서는 다음과 같이 시도 할 수 있습니다

d?.value2 , d?.value3

0

허용되는 답변과 마찬가지로 GetField대신 대신 시도해 볼 수도 있습니다 GetProperty.

d.GetType().GetField("value2").GetValue(d);

실제 Type구현 방식에 따라 GetProperty ()가 작동하지 않거나 더 빠를 수도 있습니다.


C # 3.0+의 속성과 필드의 차이 : stackoverflow.com/a/653799/2680660
Efreeto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.