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


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.NonPublicBindingFlags.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.