리플렉션이있는 개인 필드를 찾으십니까?


228

이 수업이 주어지면

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

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

속성으로 표시 할 개인 항목 _bar를 찾고 싶습니다. 가능합니까?

속성을 찾은 속성을 사용했지만 개인 멤버 필드는 사용하지 않았습니다.

개인 필드를 얻기 위해 설정해야 할 바인딩 플래그는 무엇입니까?


@Nescio : 왜 그 접근 방식을 취해야하는지 확장 할 수 있습니까? ...혜택? 아니면 단순히 선호? :)
— IAbstract

답변:


279

사용 BindingFlags.NonPublic및 BindingFlags.Instance플래그

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

11
"BindingFlags.Instance"바인딩 플래그를 제공하여이 기능을 작동시킬 수 있습니다.
— Andy McCluggage

1
나는 당신의 대답을 고쳤습니다. 그렇지 않으면 너무 혼란 스럽습니다. Abe Heidebrecht의 답변은 가장 완전했습니다.
— lubos hasko 2016 년

2
훌륭하게 작동합니다-FYI VB.NET 버전 Me.GetType (). GetFields (Reflection.BindingFlags.NonPublic 또는 Reflection.BindingFlags.Instance)
— gg.

2
인스턴스 바인딩 플래그를 사용하는 것은 인스턴스 메소드를 가져 오려는 경우에만 해당됩니다. 전용 정적 메소드를 얻으려면 (BindingFlags.NonPublic | BindingFlags.Static)
— ksun

166

속성과 마찬가지로 할 수 있습니다.

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

9
극도의 괴롭힘에 대해 미안하지만 이것은 나를 버렸습니다. GetCustomAttributes (Type)는 속성을 찾지 못하면 null을 반환하지 않고 단순히 빈 배열을 반환합니다.
— 기억 상실

42

Reflection을 사용하여 개인 변수의 값을 얻습니다.

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

리플렉션을 사용하여 개인 변수의 값을 설정하십시오.

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

여기서 objectForFooClass는 클래스 유형 Foo의 널이 아닌 인스턴스입니다.


비슷한 대답은 사용하기 쉬운 기능을 설명 GetInstanceField(typeof(YourClass), instance, "someString") as string 합니다. C #에서 개인 필드의 값을 얻는 방법은 무엇입니까?
— Michael Freidgeim 2016 년

24

개인 구성원에 반영 할 때 알아야 할 한 가지는 응용 프로그램이 중간 신뢰 수준에서 실행되는 경우 (예 : 공유 호스팅 환경에서 실행중인 경우) 해당 응용 프로그램을 찾을 수 없다는 것입니다. BindingFlags.NonPublic 옵션은 단순히 무시됩니다.


jammycakes 공유 호스팅 환경의 예를 들어 주시겠습니까? 여러 응용 프로그램을 사용하는 iis가 무엇을 얻고 있다고 생각합니까?
— 브라이언 스위니

machine.config 수준에서 IIS가 부분 신뢰로 잠긴 위치에 대해 이야기하고 있습니다. 일반적으로 요즘에는 저렴하고 불쾌한 공유 웹 호스팅 계획에서만 찾을 수 있습니다 (더 이상 사용하지 않는 것들). 서버를 완전히 제어 할 수 있다면 완전히 신뢰할 수 있으므로 기본.
— jammycakes

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

나는 필드의 이름을 모른다. 이름이없고 속성이있을 때 그것을 찾고 싶습니다.
— David Basarab

필드 이름을 찾으려면 Visual Studio에서 쉽게 수행 할 수 있습니다. 변수에 중단 점을 설정하고 해당 필드 (일반적으로 m_fieldname으로 시작하는 개인 포함)를보십시오. m_fieldname을 위의 명령으로 바꾸십시오.
— Hao Nguyen

13

확장 방법을 사용한 멋진 구문

다음과 같은 코드를 사용하여 임의 유형의 개인 필드에 액세스 할 수 있습니다.

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

이를 위해 작업을 수행 할 확장 방법을 정의해야합니다.

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
야, 이것은 내 코드에서 NLua에 노출시키지 않고 보호 된 변수에 액세스하는 데 완벽했습니다! 대박!
— tayoung

6

이 방법을 개인적으로 사용합니다

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

6

다음은 간단한 get 및 set 개인 필드 및 속성 (setter가있는 속성)을위한 몇 가지 확장 방법입니다.

사용 예 :

    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

암호:

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

예. 그러나 클래스 인스턴스 외부에서 멤버를 찾는 경우 개인 필드를 검색하도록 바인딩 플래그를 설정해야합니다.

필요한 바인딩 플래그는 다음과 같습니다. System.Reflection.BindingFlags.NonPublic


2

Google에서 이것을 검색하는 동안이 문제가 발생하여 오래된 게시물이 충돌하고 있음을 알았습니다. 그러나 GetCustomAttributes에는 두 개의 매개 변수가 필요합니다.

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

두 번째 매개 변수는 상속 계층 구조를 검색할지 여부를 지정합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.