Reflectionでプライベートフィールドを見つけますか?


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 2008

1
あなたの答えを修正しました。そうでなければ、それはあまりにも混乱しています。安倍ハイデブレヒトの答えはもっとも完全だった。
lubos hasko 2009年

2
素晴らしい作品-FYI VB.NETバージョンMe.GetType()。GetFields(Reflection.BindingFlags.NonPublic Or 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を返しません。単に空の配列を返します。
amnesia 2017年

42

リフレクションを使用してプライベート変数の値を取得します。

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のnull以外のインスタンスです。


同様の答えは使いやすい関数について説明GetInstanceField(typeof(YourClass), instance, "someString") as string していますC#でプライベートフィールドの値を取得する方法
Michael Freidgeim、2016年

24

プライベートメンバーを反映​​する際に注意する必要があることの1つは、アプリケーションが中程度の信頼で実行されている場合(たとえば、共有ホスティング環境で実行している場合)、それらを見つけられないことです- BindingFlags.NonPublicオプションは単に無視されます。


jammycakes共有ホスティング環境の例を挙げていただけますか?複数のアプリを備えたiisはあなたが得ているものだと思いますか?
ブライアンスウィーニー

IISがmachine.configレベルで部分的な信頼にロックされている場所について話している。通常、これは最近の安価で厄介な共有Webホスティングプラン(私はもう使用しません)でしか見つかりません-サーバーを完全に制御している場合、完全な信頼があるため、実際には関係ありません。デフォルト。
jammycakes 2015

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

フィールドの名前はわかりません。名前なしで、属性がその上にあるときに、それを見つけたいです。
デビッドバサラブ

フィールド名を見つけるには、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 2018

6

私はこの方法を個人的に使用しています

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

6

簡単なgetおよびsetのプライベートフィールドとプロパティ(セッター付きのプロパティ)のいくつかの拡張メソッドを次に示します。

使用例:

    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

私はこれをグーグルで検索しているときにこれに遭遇したので、私は古い投稿をぶつけていることに気づきました。ただし、GetCustomAttributesには2つのパラメーターが必要です。

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

2番目のパラメーターは、継承階層を検索するかどうかを指定します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.