Yansıma kullanarak nesne özelliğini ayarlama


323

C # bir nesne özelliği ayarlamak için yansıma kullanabilirsiniz bir yolu var mı?

Ör:

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

obj.NameYansımayı ayarlamak istiyorum . Gibi bir şey:

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

Bunu yapmanın bir yolu var mı?

Yanıtlar:


391

Evet, şunları kullanabilirsiniz Type.InvokeMember():

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

Bu, objçağrılan bir özelliğe sahip değilse Nameveya ayarlanamazsa bir istisna atar .

Başka bir yaklaşım, mülkün meta verilerini almak ve sonra ayarlamaktır. Bu, mülkün varlığını kontrol etmenize ve mülkün ayarlanabildiğinden emin olmanıza olanak tanır:

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
Tüm dizelerle ilgilenmiyorsanız, önce verileri dönüştürmek isteyebilirsiniz: var val = Convert.ChangeType(propValue, propInfo.PropertyType); kaynak: devx.com/vb2themax/Tip/19599
LostNomad311 18:12

4
alternatif olarak, kullanabilirsinizobj.GetType().GetProperty("Name")?.GetSetMethod()?.Invoke(...)
tecfield

1
CanWrite=Falsetürler için değer belirlemek imkansız , değil mi?
T.Todua

287

Ayrıca şunları da yapabilirsiniz:

Type type = target.GetType();

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

prop.SetValue (target, propertyValue, null);

Burada hedef, özelliği ayarlanacak nesnedir.


11
Bugün de aynı şeyi yaptım. Yukarıdaki harika çalışır, elbette kullanmaya çalışmadan önce pervane üzerinde boş bir kontrol yapılmalıdır.
Antony Scott

3
@AntonyScott Yanlış mülkü çağırdığınızı bilmek isteyeceğinizi düşünürdüm, bu yüzden "sessizce başarısız" kötü bir rota gibi görünüyor.
17'de jih

3
@jih Ne demek istediğini görebiliyorum, ama bu duruma gerçekten bağlı.
Antony Scott

94

Yansıma, temelde, yani

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

veya hem kolaylık hem de performans açısından yardımcı olacak kütüphaneler var; örneğin FastMember ile :

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

(bu aynı zamanda bir alanın bir mülk olup olmadığını önceden bilmenize gerek olmaması avantajına sahiptir)


Vay be, birleştirme biraz karıştı, ama cevap tekrar buldum! Teşekkür ederim, bir 'kabul et' hak ediyorsun, ama iş parçacığım birleştirildiğinden :( Tekrar teşekkürler!
halfpastfour.am

@MarcGravell, FastMember'e bakıyordum ve oldukça ilginç. Sadece ölümlüler bu büyük lib kullanmak için bir yerde bir başlangıç ​​/ öğretici var mı?
Sudhanshu Mishra

FastMember tarafından mülk türünü nasıl alabilirim?
Said Roohullah Allem

@Jahan accessor => GetMembers => Üye => Tür
Marc Gravell

mükemmel cevap! Bir oneliner hakkında iyi bir şey, aralarında kendiniz için bir anlam ifade etmeyebilecek değişkenler adında bir kullanıcı olmadığından, anlamanın çok daha hızlı olmasıdır.
Bastiaan

27

Veya Marc'ın bir astarını kendi uzatma sınıfınıza sarabilirsiniz:

public static class PropertyExtension{       

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

ve şöyle deyin:

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

İyi bir ölçü için, bir özellik değeri elde etmek için bir yöntem ekleyelim:

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

14

Evet, şunu kullanarak System.Reflection:

using System.Reflection;

...

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

13

Bunun gibi bir şey kullanın:

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

veya

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
Mülk türünü alıp daha sonra yayınladığınız kısım benim için gerçekten yararlı oldu. Mucizevi şekilde çalışır. Teşekkür ederim
Marc

12

Alanlara benzer bir şekilde de erişebilirsiniz:

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

Yansıması ile her şey açık bir kitap olabilir :) Örneğimde özel bir örnek seviyesi alanına bağlanıyoruz.


8

Özellik adlarını kullanarak bir Nesnenin özelliklerini başka bir Nesneden toplu olarak atamak istediğinizde bunu deneyebilirsiniz:

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
Merhaba ve Stack Overflow'a hoş geldiniz. Lütfen kodunuzu düzgün bir şekilde biçimlendirin ve sadece gönderinize dökmeyin, başkalarının cevabınızı anlamasına yardımcı olacaktır.
ThreeFx

0

Ben sadece ilk seviye Özellikleri değil, aynı zamanda herhangi bir derinlikte verilen nesnede iç içe özellikleri ayarlamaya izin veren bir Nuget paketi yayınladım.

İşte paket

Bir nesnenin özelliğinin değerini kökünden yoluna göre ayarlar.

Nesne karmaşık bir nesne olabilir ve özellik çok düzeyli derin iç içe özellik olabilir veya doğrudan kökün altındaki bir özellik olabilir. ObjectWriterözelliği özellik yolu parametresini kullanarak bulur ve değerini günceller. Özellik yolu, sınırlayıcı dize parametresi tarafından ayrılmış, kökten ayarlamak istediğimiz son düğüm özelliğine ziyaret edilen özelliklerin eklenmiş adlarıdır.

Kullanımı:

Özellikleri doğrudan nesne kökünün altında ayarlamak için:

Yani. LineItemsınıfın int özelliği varItemId

LineItem lineItem = new LineItem();

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

Yuvalanmış özelliği, nesne kökünün altında birden çok düzey ayarlamak için:

Yani. Invitesınıf, adlı bir özelliğe Statesahiptir ve bu özelliği Invite(Davet türü) adlı bir özelliğe Recipientsahiptir.Id .

İşleri daha da karmaşık hale getirmek için, Stateözellik bir referans türü değil, bir struct.

Nesne ağacının altındaki Id özelliğini (“outlook” dizesi değerine) tek bir satırda nasıl ayarlayacağınız aşağıda açıklanmıştır.

Invite invite = new Invite();

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

0

MarcGravell'in önerisine dayanarak, aşağıdaki statik yöntemi oluşturdum.Yöntem genel olarak FastMember kullanarak kaynak nesneden hedefe eşleşen tüm özellikleri atar

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