2009-10-14 5 views
104

Kann ich eine private Immobilie über Reflektion festlegen?Ist es möglich, Privateigentum durch Reflektion zu setzen?

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); } 
    } 
} 

Ich habe versucht, die folgenden und es funktioniert nicht, wo t eine Art Entity darstellt:

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

Ich glaube, ich kann dies tun, aber ich kann es nicht funktioniert.

+2

Ich weiß das Es ist spät, aber ich fand einen Bedarf für diesen Gedanken, ich würde mein "Warum" teilen. Ich musste die Unannehmlichkeiten einiger Software von Drittanbietern überwinden. Insbesondere verwendete ich die Crystal Reports ExportToStream-Methode. Wie diese Methode geschrieben wurde, war der Zugriff auf den internen Puffer des Streams nicht erlaubt. Um den Bericht an den Browser zu senden, musste ich den Stream in einen neuen Puffer (100K +) kopieren und dann senden. Indem ich das private '_exposable' Feld im stream Objekt auf 'true' setzte, konnte ich den internen Puffer direkt herausschicken und eine 100K + Zuweisung für jede Anfrage speichern. – Ray

+20

Warum? Angenommen, Sie verfügen über private IDs für Ihre Id-Eigenschaften für alle Domänenobjekte, und Sie möchten Repository-Tests implementieren. Dann sollten Sie nur in Ihrem Repository-Testprojekt die Id-Eigenschaft festlegen können. – bounav

+2

Ein weiteres Anwendungsszenario: Festlegen von automatisch generierten Feldern wie "Erstellungsdatum" beim Importieren von Daten. – ANeves

Antwort

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

EDIT: Da die Immobilie selbst öffentlich ist, Sie offensichtlich nicht brauchen BindingFlags.NonPublic zu verwenden, um es zu finden. Rufen Sie SetValue trotz der Setter weniger Zugänglichkeit immer noch, was Sie erwarten. Ja

+1

Was meinst du? Ich habe LINQPad ausgepeitscht und es ausprobiert und es hat funktioniert ... – Tinister

+5

Um fair zu sein, kommt es auf das Vertrauensniveau an, aber die Antwort scheint gültig zu sein. –

+2

Property-Set-Methode nicht gefunden bei System.Reflection.RuntimePropertyInfo.SetValue (Object Obj, Objektwert, BindingFlags InvokeAttr, Mappe Bindemittel, Object [] Index, CultureInfo Kultur) – CZahrobsky

97

, es ist:

/// <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

Nur um jemandes Haare zu schützen (die nur auf meinen Kopf gezogen wurden): das wird in Silverlight Laufzeiten nicht funktionieren: http://msdn.microsoft.com/de-de/library/xb5dd1f1%28v=vs. 95% 29.aspx –

+0

SetValue wäre besser als InvokeMember, da der ehemalige unterstützt passing index –

5

Sie können über den Code von abgeleiteten Typ privaten Setter Zugang

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, aber nur eine Anmerkung hier. BaseType sollte alle Eigenschaften haben, die Sie erwarten. Wenn Sie eine Eigenschaft verbergen (ohne sich daran zu erinnern, dass Sie dies getan haben), könnte dies dazu führen, dass einige Haare herausgezogen werden. – 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

Keine von diesen für mich gearbeitet, und mein Eigentum Name war einzigartig, also habe ich gerade folgendes benutzt:

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; 
     } 
    } 
}