2009-10-14 5 views
104

리플렉션을 통해 비공개 속성을 설정할 수 있습니까?리플렉션을 통해 전용 속성을 설정할 수 있습니까?

var t = typeof(Entity); 
var mi = t.GetMethod("set_CreatedOn", BindingFlags.Instance | BindingFlags.NonPublic); 

나는이 작업을 수행 할 수 있습니다 생각하지만 난 그것을 밖으로 작동하지 않을 수 있습니다 tEntity의 유형을 나타내는 나는 다음과 같은 시도하고 그것이 작동하지 않는

public abstract class Entity 
{ 
    private int _id; 
    private DateTime? _createdOn; 
    public virtual T Id 
    { 
     get { return _id; } 
     private set { ChangePropertyAndNotify(ref _id, value, x => Id); } 
    } 
    public virtual DateTime? CreatedOn 
    { 
     get { return _createdOn; } 
     private set { ChangePropertyAndNotify(ref _createdOn, value, x => CreatedOn); } 
    } 
} 

.

+2

나는 이것을 알고 있습니다. 늦었지만, 나는이 이유에 대한 필요성을 발견했다. 나는 나의 '왜'를 나눌 것이다. 제 3 자 소프트웨어에서 불편을 극복해야했습니다. 특히 Crystal Reports ExportToStream 메서드를 사용하고있었습니다. 이 메소드가 작성된 방식에서는 스트림의 내부 버퍼에 액세스 할 수 없습니다. 보고서를 브라우저에 보내려면 스트림을 새 버퍼 (100K 이상)에 복사 한 다음 보내야했습니다. 스트림 객체의 '_exposable'필드를 'true'로 설정하면 각 요청에 100K + 할당을 저장하면서 직접 내부 버퍼를 보낼 수있었습니다. – Ray

+20

왜? 모든 도메인 객체의 ID 속성에 개인 설정자가 있고 저장소 테스트를 구현하려고한다고 가정 해 보겠습니다. 그런 다음 저장소 테스트 프로젝트에서만 Id 속성을 설정할 수 있기를 원할 것이다. – bounav

+2

또 다른 사용 시나리오 : 데이터를 가져올 때 "생성 날짜"와 같은 자동 생성 필드 설정. – ANeves

답변

67
t.GetProperty("CreatedOn") 
    .SetValue(obj, new DateTime(2009, 10, 14), null); 

편집 : 건물 자체가 공개되어 있기 때문에, 당신은 분명히 그것을 찾기 위해 BindingFlags.NonPublic를 사용할 필요가 없습니다. setter의 액세스 가능성이 낮더라도 SetValue을 호출해도 예상 한대로 작동합니다.

+1

무엇을 의미합니까? 나는 LINQPad를 채찍질하고 이것을 시험해 보았다. ... – Tinister

+5

공평하게 말하자면, 신뢰 수준에 달려 있지만 대답은 유효하다. –

+2

System.Reflection.RuntimePropertyInfo.SetValue에서 속성 집합 메서드를 찾을 수 없습니다 (개체 obj, 개체 값, BindingFlags invokeAttr, 바인더 바인더, 개체 [] 인덱스, CultureInfo culture) – CZahrobsky

97

예, 그것이 :

/// <summary> 
    /// Returns a _private_ Property Value from a given Object. Uses Reflection. 
    /// Throws a ArgumentOutOfRangeException if the Property is not found. 
    /// </summary> 
    /// <typeparam name="T">Type of the Property</typeparam> 
    /// <param name="obj">Object from where the Property Value is returned</param> 
    /// <param name="propName">Propertyname as string.</param> 
    /// <returns>PropertyValue</returns> 
    public static T GetPrivatePropertyValue<T>(this object obj, string propName) 
    { 
     if (obj == null) throw new ArgumentNullException("obj"); 
     PropertyInfo pi = obj.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 
     if (pi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName)); 
     return (T)pi.GetValue(obj, null); 
    } 

    /// <summary> 
    /// Returns a private Property Value from a given Object. Uses Reflection. 
    /// Throws a ArgumentOutOfRangeException if the Property is not found. 
    /// </summary> 
    /// <typeparam name="T">Type of the Property</typeparam> 
    /// <param name="obj">Object from where the Property Value is returned</param> 
    /// <param name="propName">Propertyname as string.</param> 
    /// <returns>PropertyValue</returns> 
    public static T GetPrivateFieldValue<T>(this object obj, string propName) 
    { 
     if (obj == null) throw new ArgumentNullException("obj"); 
     Type t = obj.GetType(); 
     FieldInfo fi = null; 
     while (fi == null && t != null) 
     { 
      fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 
      t = t.BaseType; 
     } 
     if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName)); 
     return (T)fi.GetValue(obj); 
    } 

    /// <summary> 
    /// Sets a _private_ Property Value from a given Object. Uses Reflection. 
    /// Throws a ArgumentOutOfRangeException if the Property is not found. 
    /// </summary> 
    /// <typeparam name="T">Type of the Property</typeparam> 
    /// <param name="obj">Object from where the Property Value is set</param> 
    /// <param name="propName">Propertyname as string.</param> 
    /// <param name="val">Value to set.</param> 
    /// <returns>PropertyValue</returns> 
    public static void SetPrivatePropertyValue<T>(this object obj, string propName, T val) 
    { 
     Type t = obj.GetType(); 
     if (t.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) == null) 
      throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName)); 
     t.InvokeMember(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, obj, new object[] { val }); 
    } 

    /// <summary> 
    /// Set a private Property Value on a given Object. Uses Reflection. 
    /// </summary> 
    /// <typeparam name="T">Type of the Property</typeparam> 
    /// <param name="obj">Object from where the Property Value is returned</param> 
    /// <param name="propName">Propertyname as string.</param> 
    /// <param name="val">the value to set</param> 
    /// <exception cref="ArgumentOutOfRangeException">if the Property is not found</exception> 
    public static void SetPrivateFieldValue<T>(this object obj, string propName, T val) 
    { 
     if (obj == null) throw new ArgumentNullException("obj"); 
     Type t = obj.GetType(); 
     FieldInfo fi = null; 
     while (fi == null && t != null) 
     { 
      fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 
      t = t.BaseType; 
     } 
     if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName)); 
     fi.SetValue(obj, val); 
    } 
+7

그냥 내 머리에 뽑힌 안전한 사람에게만 줘야합니다. Silverlight 런타임에서는 작동하지 않습니다. http://msdn.microsoft.com/de-de/library/xb5dd1f1%28v=vs. 95 % 29.aspx –

+0

SetValue는 InvokeMember보다 좋을 것입니다. 이전에서는 인덱스 –

5

당신은 코드

public static void SetProperty(object instance, string propertyName, object newValue) 
{ 
    Type type = instance.GetType(); 

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

    prop.SetValue(instance, newValue, null); 
} 
+0

+1을 전달하기 때문에 +1하지만 단지 여기에 유의하십시오. BaseType은 여러분이 기대하는 모든 속성을 가져야한다. 재산을 숨기고 있다면 (그렇게했다는 사실을 기억하지 않고), 머리카락이 빠져 나갈 수 있습니다. – ouflak

0
//mock class 
    public class Person{ 
     public string Name{get; internal set;} 
    } 

    // works for all types, update private field through reflection 
    public static T ReviveType<T>(T t, string propertyName, object newValue){ 
     // add a check here that the object t and propertyName string are not null 
     PropertyInfo pi = t.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); 
     pi.SetValue(t, newValue, null); 
     return t; 
    } 

    // check the required function 
    void Main() 
    { 
     var p = new Person(){Name="John"}; 
     Console.WriteLine("Name: {0}",p.Name); 

     //box the person to object, just to see that the method never care about what type you pass it 
     object o = p; 
     var updatedPerson = ReviveType<Object>(o, "Name", "Webber") as Person; 

     //check if it updated person instance 
     Console.WriteLine("Name: {0}",updatedPerson.Name); 
    } 



// Console Result: ------------------- 
Name: John 
Name: Webber 
3

이 중에 나를 위해 일하지 않고, 내 재산의 이름은 독특를 통해 파생 유형에서 개인 세터에 액세스 할 수 있습니다, 그래서 방금 다음과 같이 사용했습니다.

public static void SetPrivatePropertyValue<T>(T obj, string propertyName, object newValue) 
{ 
    // add a check here that the object obj and propertyName string are not null 
    foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) 
    { 
     if (fi.Name.ToLower().Contains(propertyName.ToLower())) 
     { 
      fi.SetValue(obj, newValue); 
      break; 
     } 
    } 
} 
관련 문제