Reflection ile özel bir alan mı arıyorsunuz?


228

Bu sınıf verildi

class Foo
{
    // Want to find _bar with reflection
    [SomeAttribute]
    private string _bar;

    public string BigBar
    {
        get { return this._bar; }
    }
}

Bir özellik ile işaretleyeceğim _bar özel öğesini bulmak istiyorum. Mümkün mü?

Bunu bir özellik aradığım özelliklerle yaptım, ama asla özel bir üye alanı.

Özel alanları almak için ayarlamam gereken bağlayıcı bayraklar nelerdir?


@Nescio: Neden bu yaklaşımı benimseyeceğine bakabilir misin? ...faydalar? Veya sadece tercih mi? :)
IA

Yanıtlar:


279

Kullanım BindingFlags.NonPublicve BindingFlags.Instancebayraklar

FieldInfo[] fields = myType.GetFields(
                         BindingFlags.NonPublic | 
                         BindingFlags.Instance);

11
Ben de sadece "BindingFlags.Instance" bağlama bayrağı sağlayarak işe alabilir.
Andy McCluggage

1
Cevabını düzelttim. Aksi halde çok kafa karıştırıcı. Abe Heidebrecht'in cevabı en eksiksizdi.
lubos hasko

2
Harika çalışıyor - FYI VB.NET sürümü Me.GetType (). GetFields (Reflection.BindingFlags.NonPublic veya Reflection.BindingFlags.Instance)
gg.

2
Örnek bağlama bayrağını kullanmak yalnızca örnek yöntemlerini almak istiyorsanız kullanılır. Özel bir statik yöntem almak istiyorsanız (
BindingFlags.NonPublic

166

Bunu bir mülkte olduğu gibi yapabilirsiniz:

FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null)
    ...

9
Aşırı nekro gönderme için üzgünüm, ama bu beni attı. Özellik bulunmazsa GetCustomAttributes (Tür) null değerini döndürmez, boş bir dizi döndürür.
amnesia

42

Yansıma kullanarak özel değişkenin değerini alın:

var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass);

Yansıma kullanarak özel değişken için değeri ayarlayın:

typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue");

Burada objectForFooClass, Foo sınıf türü için boş olmayan bir örnektir.


Benzer cevap kullanımı kolay işlevi açıklar GetInstanceField(typeof(YourClass), instance, "someString") as string C # özel alan değerini almak nasıl?
Michael Freidgeim

24

Özel üyelere yansıtırken dikkat etmeniz gereken bir şey, uygulamanız orta güvende çalışıyorsa (örneğin, paylaşılan bir barındırma ortamında çalışırken) onları bulamayacağıdır. BindingFlags.NonPublic seçeneği yok sayılır.


jammycakes paylaşılan barındırma ortamına bir örnek verebilir misiniz? sanırım birden fazla uygulama ile iis alıyorsanız budur?
Brian Sweeney

IIS'nin machine.config düzeyinde kısmi güven için kilitlendiği yer hakkında konuşuyorum. Genellikle sadece bu günlerde ucuz ve kötü paylaşılan web barındırma planlarında bulabilirsiniz (artık kullanmadığım beğeniler) - sunucunuz üzerinde tam kontrole sahipseniz, tam güven olduğundan varsayılan.
jammycakes

18
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)

Alanın adını bilmiyorum. Adı olmadan ve özniteliğin üstünde olduğunda bulmak istiyorum.
David Basarab

Alan adını bulmak için Visual Studio'da yapmak kolaydır. Değişkende kesme noktası ayarlayın, alanlarını görüntüleyin (özel dahil, genellikle m_fieldname ile başlar). Bu m_fieldname yerine yukarıdaki komutu yazın.
Hao Nguyen

13

Uzatma Yöntemi ile Güzel Sözdizimi

Rastgele bir türdeki herhangi bir özel alana aşağıdaki kodla erişebilirsiniz:

Foo foo = new Foo();
string c = foo.GetFieldValue<string>("_bar");

Bunun için işi sizin için yapacak bir uzantı yöntemi tanımlamanız gerekir:

public static class ReflectionExtensions {
    public static T GetFieldValue<T>(this object obj, string name) {
        // Set the flags so that private and public fields from instances will be found
        var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
        var field = obj.GetType().GetField(name, bindingFlags);
        return (T)field?.GetValue(obj);
    }
}

1
Dostum, bu benim kodum NLua maruz kalmadan korumalı bir değişken erişmek için MÜKEMMEL oldu! Müthiş!
tayoung

6

Bu yöntemi şahsen kullanıyorum

if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{ 
    // do stuff
}

6

Basit alma ve ayarlama özel alanları ve özellikleri (ayarlayıcılı özellikler) için bazı uzantı yöntemleri şunlardır:

kullanım örneği:

    public class Foo
    {
        private int Bar = 5;
    }

    var targetObject = new Foo();
    var barValue = targetObject.GetMemberValue("Bar");//Result is 5
    targetObject.SetMemberValue("Bar", 10);//Sets Bar to 10

Kod:

    /// <summary>
    /// Extensions methos for using reflection to get / set member values
    /// </summary>
    public static class ReflectionExtensions
    {
        /// <summary>
        /// Gets the public or private member using reflection.
        /// </summary>
        /// <param name="obj">The source target.</param>
        /// <param name="memberName">Name of the field or property.</param>
        /// <returns>the value of member</returns>
        public static object GetMemberValue(this object obj, string memberName)
        {
            var memInf = GetMemberInfo(obj, memberName);

            if (memInf == null)
                throw new System.Exception("memberName");

            if (memInf is System.Reflection.PropertyInfo)
                return memInf.As<System.Reflection.PropertyInfo>().GetValue(obj, null);

            if (memInf is System.Reflection.FieldInfo)
                return memInf.As<System.Reflection.FieldInfo>().GetValue(obj);

            throw new System.Exception();
        }

        /// <summary>
        /// Gets the public or private member using reflection.
        /// </summary>
        /// <param name="obj">The target object.</param>
        /// <param name="memberName">Name of the field or property.</param>
        /// <returns>Old Value</returns>
        public static object SetMemberValue(this object obj, string memberName, object newValue)
        {
            var memInf = GetMemberInfo(obj, memberName);


            if (memInf == null)
                throw new System.Exception("memberName");

            var oldValue = obj.GetMemberValue(memberName);

            if (memInf is System.Reflection.PropertyInfo)
                memInf.As<System.Reflection.PropertyInfo>().SetValue(obj, newValue, null);
            else if (memInf is System.Reflection.FieldInfo)
                memInf.As<System.Reflection.FieldInfo>().SetValue(obj, newValue);
            else
                throw new System.Exception();

            return oldValue;
        }

        /// <summary>
        /// Gets the member info
        /// </summary>
        /// <param name="obj">source object</param>
        /// <param name="memberName">name of member</param>
        /// <returns>instanse of MemberInfo corresponsing to member</returns>
        private static System.Reflection.MemberInfo GetMemberInfo(object obj, string memberName)
        {
            var prps = new System.Collections.Generic.List<System.Reflection.PropertyInfo>();

            prps.Add(obj.GetType().GetProperty(memberName,
                                               System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance |
                                               System.Reflection.BindingFlags.FlattenHierarchy));
            prps = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where( prps,i => !ReferenceEquals(i, null)));
            if (prps.Count != 0)
                return prps[0];

            var flds = new System.Collections.Generic.List<System.Reflection.FieldInfo>();

            flds.Add(obj.GetType().GetField(memberName,
                                            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance |
                                            System.Reflection.BindingFlags.FlattenHierarchy));

            //to add more types of properties

            flds = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(flds, i => !ReferenceEquals(i, null)));

            if (flds.Count != 0)
                return flds[0];

            return null;
        }

        [System.Diagnostics.DebuggerHidden]
        private static T As<T>(this object obj)
        {
            return (T)obj;
        }
    }

4

Evet, ancak Bağlama bayraklarınızı özel alanları arayacak şekilde ayarlamanız gerekir (sınıf örneğinin dışında üye arıyorsanız).

İhtiyacınız olacak bağlama bayrağı: System.Reflection.BindingFlags.NonPublic


2

Eski bir gönderiyi çarptığımı fark ettim. Ancak GetCustomAttributes iki parametre gerektirir.

typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0);

İkinci parametre, miras hiyerarşisinde arama yapmak isteyip istemediğinizi belirtir

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.