Find a private field with Reflection?
Asked Answered
M

11

279

Given this class

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

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

I want to find the private item _bar that I will mark with a attribute. Is that possible?

I have done this with properties where I have looked for an attribute, but never a private member field.

What are the binding flags that I need to set to get the private fields?

Magnoliamagnoliaceous answered 18/9, 2008 at 19:16 Comment(0)
Y
352

Use BindingFlags.NonPublic and BindingFlags.Instance flags

FieldInfo[] fields = myType.GetFields(
                         BindingFlags.NonPublic | 
                         BindingFlags.Instance);
Yolk answered 18/9, 2008 at 19:22 Comment(5)
I could only get this to work by also supplying the "BindingFlags.Instance" binding flag.Anthology
I have fixed your answer. It's too confusing otherwise. Abe Heidebrecht's answer was the most complete though.Decrescendo
Works great - FYI VB.NET version Me.GetType().GetFields(Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)Ronironica
Using the instance binding flag is only if you want to get instance methods. If you wanted to get a private static method you can use (BindingFlags.NonPublic | BindingFlags.Static)Acclamation
BindingFlags.Instance trips me EVERY time I use reflection on non-public members. If you use GetFields() with Default=0 BindingFlags, you get instance members automatically. But when you set a binding flag explicitly, it deletes the default inclusion of instance members. It makes no sense. Flags enums should be additive.Discontinuance
T
181

You can do it just like with a property:

FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttribute(typeof(SomeAttribute)) != null)
    ...
Trapezius answered 18/9, 2008 at 19:21 Comment(1)
Sorry for extreme necro-posting, but this threw me off. GetCustomAttributes(Type) will not return null if the attribute isn't found, it simply returns an empty array.Seagirt
H
66

Get private variable's value using Reflection:

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

Set value for private variable using Reflection:

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

Where objectForFooClass is a non null instance for the class type Foo.

Hussey answered 9/12, 2011 at 8:19 Comment(1)
Similar answer describes easy to use function GetInstanceField(typeof(YourClass), instance, "someString") as string How to get the value of private field in C#?Faradic
N
43

Nice Syntax With Extension Method

You can access any private field of an arbitrary type with code like this:

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

For that you need to define an extension method that will do the work for you:

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);
    }
}
Newcomer answered 29/9, 2017 at 12:28 Comment(1)
Dude, this was PERFECT for accessing a protected variable without exposing it to NLua in my code! Awesome!Treasatreason
S
26

One thing that you need to be aware of when reflecting on private members is that if your application is running in medium trust (as, for instance, when you are running on a shared hosting environment), it won't find them -- the BindingFlags.NonPublic option will simply be ignored.

Science answered 18/9, 2008 at 19:26 Comment(2)
jammycakes could you please give an example of shared hosting environment? i'm thinking iis with multiple apps is what your're getting?Ives
I'm talking about where IIS is locked down to partial trust at the machine.config level. You usually only find this on cheap-and-nasty shared web hosting plans these days (the likes of which I no longer use) -- if you have full control over your server then it won't really be relevant since full trust is the default.Science
D
19
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)
Declaration answered 18/9, 2008 at 19:19 Comment(2)
I won't know the name of the field. I want to find it without the name and when the attribute is on it.Magnoliamagnoliaceous
To find the field name, it's easy to do in Visual Studio. Set breakpoint at the variable, view its fields (including the private, usually started with m_fieldname). Replace that m_fieldname in to the command above.Yangyangtze
P
7

Here is some extension methods for simple get and set private fields and properties (properties with setter):

usage example:

    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

Code:

    /// <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;
        }
    }
Petrinapetrine answered 30/5, 2014 at 11:54 Comment(0)
R
6

I use this method personally

if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{ 
    // do stuff
}
Rosabelle answered 24/11, 2012 at 7:49 Comment(0)
S
4

Yes, however you will need to set your Binding flags to search for private fields (if your looking for the member outside of the class instance).

The binding flag you will need is: System.Reflection.BindingFlags.NonPublic

Sillimanite answered 18/9, 2008 at 19:18 Comment(0)
K
4

If your .Net framework is greater than 4.5. You can use GetRuntimeFields method.

This method returns all fields that are defined on the specified type, including inherited, non-public, instance, and static fields.

https://learn.microsoft.com/en-us/dotnet/api/system.reflection.runtimereflectionextensions.getruntimefields?view=net-6.0

var foo = new Foo();
var fooFields = foo.GetType().GetRuntimeFields()
Kidd answered 11/7, 2022 at 5:22 Comment(0)
L
2

I came across this while searching for this on google so I realise I'm bumping an old post. However the GetCustomAttributes requires two params.

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

The second parameter specifies whether or not you wish to search the inheritance hierarchy

Lulu answered 31/3, 2011 at 11:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.