리플렉션을 사용하여 객체 속성 설정


323

C #에서 리플렉션을 사용하여 객체 속성을 설정할 수있는 방법이 있습니까?

전의:

MyObject obj = new MyObject();
obj.Name = "Value";

obj.Name반사 로 설정하고 싶습니다 . 다음과 같은 것 :

Reflection.SetProperty(obj, "Name") = "Value";

이 방법이 있습니까?

답변:


391

예, 다음을 사용할 수 있습니다 Type.InvokeMember().

using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
    Type.DefaultBinder, obj, "Value");

obj이라는 속성 Name이 없거나 설정할 수없는 경우 예외가 발생합니다 .

또 다른 방법은 속성의 메타 데이터를 가져 와서 설정하는 것입니다. 이를 통해 속성의 존재를 확인하고 설정할 수 있는지 확인할 수 있습니다.

using System.Reflection;
MyObject obj = new MyObject();
PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance);
if(null != prop && prop.CanWrite)
{
    prop.SetValue(obj, "Value", null);
}

73
모든 문자열을 다루지 않는다면 먼저 데이터를 변환하고 싶을 것입니다 : var val = Convert.ChangeType(propValue, propInfo.PropertyType); source : devx.com/vb2themax/Tip/19599
LostNomad311

4
또는 obj.GetType().GetProperty("Name")?.GetSetMethod()?.Invoke(...)
tecfield를

1
CanWrite=False유형에 대한 가치를 설정하는 것이 불가능 합니까?
T.Todua

287

당신은 또한 할 수 있습니다 :

Type type = target.GetType();

PropertyInfo prop = type.GetProperty("propertyName");

prop.SetValue (target, propertyValue, null);

여기서 target은 속성이 설정 될 객체입니다.


11
오늘도 똑같은 일을했습니다. 위의 내용은 훌륭하게 작동하며, 사용하기 전에 소품에 대해 null 검사를 수행해야합니다.
Antony Scott

3
@AntonyScott 나는 당신이 잘못된 재산을 불러 내고 있는지 알고 싶을 것이라고 생각합니다. 그래서 "조용히 실패"는 나쁜 코스처럼 보입니다.
jih

3
@jih 당신의 요점을 볼 수 있지만 상황에 따라 다릅니다.
Antony Scott

94

반사, 기본적으로, 즉

myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null);

또는 편의성과 성능 측면에서 모두 도움이되는 라이브러리가 있습니다. 예를 들어 FastMember :

var wrapped = ObjectAccessor.Create(obj); 
wrapped[property] = "Bob";

(또한 필드 대 속성인지 사전에 알 필요가 없다는 이점이 있습니다)


와우, 합병으로 조금 혼란 스러웠지만 다시 답을 찾았습니다! 감사합니다, 당신은 '동의'를받을 자격이 있지만 내 스레드가 병합
되었으므로

@ MarcGravell, 나는 FastMember를보고 있었고 꽤 흥미 롭습니다. 필사자들이이 위대한 도서관을 사용할 수있는 시작 / 튜토리얼이 있습니까?
Sudhanshu Mishra

FastMember로 부동산 유형을 어떻게 구할 수 있습니까?
말했다 Roohullah Allem

@Jahan 접근 자 => GetMembers => 멤버 => 유형
Marc Gravell

좋은 답변입니다! oneliner에 대한 좋은 점은 이해하기가 훨씬 빠르다는 것입니다. 그 사이에 사용자가 이해할 수없는 변수라는 사용자 이름이 없기 때문에 ..
Bastiaan

27

또는 Marc의 하나의 라이너를 자신의 확장 클래스 안에 넣을 수 있습니다.

public static class PropertyExtension{       

   public static void SetPropertyValue(this object obj, string propName, object value)
    {
        obj.GetType().GetProperty(propName).SetValue(obj, value, null);
    }
}

다음과 같이 호출하십시오.

myObject.SetPropertyValue("myProperty", "myValue");

좋은 측정을 위해 속성 값을 얻는 방법을 추가해 보겠습니다.

public static object GetPropertyValue(this object obj, string propName)
{
        return obj.GetType().GetProperty(propName).GetValue (obj, null);
}

14

예, 다음을 사용합니다 System.Reflection.

using System.Reflection;

...

    string prop = "name";
    PropertyInfo pi = myObject.GetType().GetProperty(prop);
    pi.SetValue(myObject, "Bob", null);

13

다음과 같은 것을 사용하십시오 :

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
   {
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
    property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null);
   }
}

또는

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
   {
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
    Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
    object safeValue = (value == null) ? null : Convert.ChangeType(value, t);

    property.SetValue(p_object, safeValue, null);
   }
}

2
속성 유형을 얻은 다음 캐스팅하는 부분이 정말 유용했습니다. 그것은 매력처럼 작동합니다. 감사합니다
Marc

12

비슷한 방식으로 필드에 액세스 할 수도 있습니다.

var obj=new MyObject();
FieldInfo fi = obj.GetType().
  GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(obj,value)

리플렉션을 통해 모든 것이 열린 책이 될 수 있습니다.) 내 예제에서는 개인 인스턴스 레벨 필드에 바인딩합니다.


8

속성 이름을 사용하여 다른 개체에서 개체의 속성을 대량 할당하려는 경우이 기능을 사용해 볼 수 있습니다.

public static void Assign(this object destination, object source)
    {
        if (destination is IEnumerable && source is IEnumerable)
        {
            var dest_enumerator = (destination as IEnumerable).GetEnumerator();
            var src_enumerator = (source as IEnumerable).GetEnumerator();
            while (dest_enumerator.MoveNext() && src_enumerator.MoveNext())
                dest_enumerator.Current.Assign(src_enumerator.Current);
        }
        else
        {
            var destProperties = destination.GetType().GetProperties();
            foreach (var sourceProperty in source.GetType().GetProperties())
            {
                foreach (var destProperty in destProperties)
                {
                    if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                    {
                        destProperty.SetValue(destination,     sourceProperty.GetValue(source, new object[] { }), new object[] { });
                        break;
            }
        }
    }
}

2
스택 오버플로에 오신 것을 환영합니다. 게시물에 코드를 덤프하지 말고 코드를 올바르게 형식화하십시오. 다른 사람이 귀하의 답변을 이해하는 데 도움이됩니다.
ThreeFx

0

방금 첫 번째 수준의 속성뿐만 아니라 주어진 객체에 중첩 속성을 설정할 수있는 Nuget 패키지를 방금 게시했습니다.

여기 패키지가 있습니다

루트에서 경로로 객체의 속성 값을 설정합니다.

개체는 복잡한 개체 일 수 있으며 속성은 다중 수준의 딥 중첩 속성이거나 루트 바로 아래에있는 속성 일 수 있습니다. ObjectWriter속성 경로 매개 변수를 사용하여 속성을 찾고 값을 업데이트합니다. 속성 경로는 루트에서 우리가 설정하려는 끝 노드 속성까지 방문한 속성의 추가 된 이름으로 구분자 문자열 매개 변수로 구분됩니다.

용법:

오브젝트 루트 바로 아래에 특성을 설정하려면 다음을 수행하십시오.

즉. LineItem클래스에는라는 int 속성이 있습니다ItemId

LineItem lineItem = new LineItem();

ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);

객체 루트 아래에 여러 수준의 중첩 속성을 설정하려면 다음을 수행하십시오.

즉. Inviteclass에는이라는 속성 State이 있으며,이 속성에는 Invite(초대 유형)이라는 속성 Recipient이 있으며, 속성에는 속성이 Id있습니다.

일을 더욱 복잡하게하기 위해이 State속성은 참조 유형이 아닙니다 struct.

개체 트리의 맨 아래에 Id 속성 (문자열 값 "Outlook")을 한 줄로 설정하는 방법은 다음과 같습니다.

Invite invite = new Invite();

ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");

0

MarcGravell의 제안에 따라 다음과 같은 정적 메소드를 구성했습니다.이 메소드는 일반적으로 FastMember를 사용하여 소스 객체에서 대상으로 일치하는 모든 속성을 할당합니다.

 public static void DynamicPropertySet(object source, object target)
    {
        //SOURCE
        var src_accessor = TypeAccessor.Create(source.GetType());
        if (src_accessor == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var src_members = src_accessor.GetMembers();
        if (src_members == null)
        {
            throw new ApplicationException("Could not fetch members!");
        }
        var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
        var src_class_propNames = src_class_members.Select(x => x.Name);
        var src_propNames = src_members.Except(src_class_members).Select(x => x.Name);

        //TARGET
        var trg_accessor = TypeAccessor.Create(target.GetType());
        if (trg_accessor == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var trg_members = trg_accessor.GetMembers();
        if (trg_members == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
        var trg_class_propNames = trg_class_members.Select(x => x.Name);
        var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name);



        var class_propNames = trg_class_propNames.Intersect(src_class_propNames);
        var propNames = trg_propNames.Intersect(src_propNames);

        foreach (var propName in propNames)
        {
            trg_accessor[target, propName] = src_accessor[source, propName];
        }
        foreach (var member in class_propNames)
        {
            var src = src_accessor[source, member];
            var trg = trg_accessor[target, member];
            if (src != null && trg != null)
            {
                DynamicPropertySet(src, trg);
            }
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.