Özel mülkiyeti yansıtma yoluyla belirlemek mümkün müdür?


125

Yansıma yoluyla özel bir mülk belirleyebilir miyim?

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

Aşağıdakileri denedim ve çalışmıyor, burada tbir tür temsil ediyor Entity:

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

Sanırım bunu yapabilirim ama çözemiyorum.


2
Geç olduğunu biliyorum ama bu düşünceye 'neden'imi paylaşacağım diye bir ihtiyaç buldum. Bazı üçüncü taraf yazılımlardaki bir rahatsızlığın üstesinden gelmem gerekiyordu. Özellikle, Crystal Reports ExportToStream yöntemini kullanıyordum. Bu yöntemin yazılma şekli, akışın dahili tamponuna erişime izin verilmedi. Raporu tarayıcıya göndermek için, akışı yeni bir arabelleğe (100K +) kopyalayıp sonra göndermem gerekiyordu. Akış nesnesindeki özel '_exposable' alanını 'true' olarak ayarlayarak, dahili arabelleği doğrudan gönderebildim ve her istekte 100K'dan fazla ayırma kaydedebildim.
Ray

20
Neden? Tüm etki alanı nesnenizdeki Id özelliklerinizde özel ayarlayıcılarınız olduğunu ve depo testleri uygulamak istediğinizi varsayalım. Daha sonra, yalnızca arşiv testi projenizde Id özelliğini ayarlayabilmek isteyeceksiniz.
bounav

2
Başka bir kullanım senaryosu: verileri içe aktarırken "oluşturma tarihi" gibi otomatik olarak oluşturulan alanların ayarlanması.
ANeves

Başka bir neden, mümkün olup olmadığını merak ediyorum. Bu soruyu böyle görmeye başladım.
Caleb Mauer

Yanıtlar:


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

DÜZENLEME: Mülkün kendisi halka açık olduğundan, görünüşe göre BindingFlags.NonPubliconu bulmak için kullanmanıza gerek yok . SetValueDaha az erişilebilirliğe sahip ayarlayıcıya rağmen arama yapmak beklediğinizi yine de yapıyor.


5
Adil olmak gerekirse, güven düzeyine bağlıdır, ancak cevap geçerli görünüyor.
Marc Gravell

4
Özellik kümesi yöntemi System.Reflection.RuntimePropertyInfo.SetValue adresinde bulunamadı (Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object [] indeksi, CultureInfo kültürü)
CZahrobsky

1
Sanal bir özellik kullanmıyorsam bu benim için iyi çalışıyor. Bir sanal özelliğe sahip Değeri ayarlarsam, bu çalışmıyor gibi görünüyor.
JonathanPeel

105

Evet öyle:

/// <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
Başka birinin saçını güvende tutmak için (sadece kafamdan çıkarılan saç): bu Silverlight çalışma zamanlarında işe yaramaz: msdn.microsoft.com/de-de/library/xb5dd1f1%28v=vs.95%29.aspx
Marc Wittke

SetValue endeksi geçen eski desteklerin beri InvokeMember daha iyi olurdu
Chris Xue

8

Özel ayarlayıcıya kod aracılığıyla türetilmiş türden erişebilirsiniz

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

+1, Ama burada sadece bir not. BaseType, beklediğiniz tüm özelliklere sahip olmalıdır. Bir mülkü saklıyorsanız (bunu yaptığınızı hatırlamadan), bazı tüylerin çekilmesine neden olabilir.
ouflak

3

Bunların hiçbiri benim için işe yaramadı ve mülk adım benzersizdi, bu yüzden sadece şunu kullandım:

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

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.