358

私のクラスにはプライベート メソッドのグループがあり、入力値に基づいて動的に呼び出す必要があります。呼び出しコードとターゲット メソッドの両方が同じインスタンスにあります。コードは次のようになります。

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });

この場合、GetMethod()プライベート メソッドは返されません。プライベートメソッドを見つけるために何BindingFlagsを提供する必要がありますか?GetMethod()

4

11 に答える 11

558

BindingFlags を受け入れるのオーバーロードされたバージョンGetMethodを使用するようにコードを変更するだけです。

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, 
    BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });

BindingFlags 列挙ドキュメントは次のとおりです。

于 2008-09-25T19:33:11.583 に答える
72

BindingFlags.NonPublicそれ自体では結果を返しません。結局のところ、それを組み合わせるとBindingFlags.Instanceうまくいきます。

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, 
    BindingFlags.NonPublic | BindingFlags.Instance);
于 2008-09-25T19:46:00.647 に答える
53

本当にトラブルに巻き込まれたい場合は、拡張メソッドを記述して簡単に実行できるようにします。

static class AccessExtensions
{
    public static object call(this object o, string methodName, params object[] args)
    {
        var mi = o.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
        if (mi != null) {
            return mi.Invoke (o, args);
        }
        return null;
    }
}

そして使用法:

    class Counter
    {
        public int count { get; private set; }
        void incr(int value) { count += value; }
    }

    [Test]
    public void making_questionable_life_choices()
    {
        Counter c = new Counter ();
        c.call ("incr", 2);             // "incr" is private !
        c.call ("incr", 3);
        Assert.AreEqual (5, c.count);
    }
于 2014-08-20T22:27:50.603 に答える
22

Microsoft は最近、リフレクション API を変更して、これらの回答のほとんどを廃止しました。以下は、最新のプラットフォーム (Xamarin.Forms および UWP を含む) で機能するはずです。

obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);

または拡張メソッドとして:

public static object InvokeMethod<T>(this T obj, string methodName, params object[] args)
{
    var type = typeof(T);
    var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
    return method.Invoke(obj, args);
}

ノート:

  • 目的のメソッドがジェネリックのスーパークラスにある場合は、スーパークラスobjT型に明示的に設定する必要があります。

  • メソッドが非同期の場合は、 を使用できますawait (Task) obj.InvokeMethod(…)

于 2017-01-08T04:35:50.123 に答える
9

これは継承ではできないと確信していますか?リフレクションは、問題を解決するときに最後に確認する必要があるものです。これにより、リファクタリング、コードの理解、および自動分析がより困難になります。

dynMethod をオーバーライドする DrawItem1、DrawItem2 などのクラスが必要なようです。

于 2008-09-25T19:29:42.963 に答える
9

特に非公開メンバーへの反省は間違っている

  • リフレクションはタイプ セーフを破ります。(もう) 存在しない、または間違ったパラメーターを使用して、またはパラメーターが多すぎるか、十分でない、または間違った順序でメソッドを呼び出そうとすることができます (これは私のお気に入りです :) )。ちなみに、戻り値の型も変更される可能性があります。
  • 反射が遅い。

プライベート メンバー リフレクションはカプセル化の原則を破るため、コードを次のように公開します。

  • クラスの内部動作を処理する必要があるため、コードの複雑さが増します。隠されているものは隠されたままであるべきです。
  • コードはコンパイルされますが、メソッドの名前が変更された場合は実行されないため、コードを簡単に壊すことができます。
  • プライベート コードが壊れやすくなります。プライベート コードは、そのように呼び出されることを意図していないためです。おそらく、プライベート メソッドは、呼び出される前に何らかの内部状態を想定しています。

とにかくそれをしなければならない場合はどうなりますか?

サードパーティに依存したり、公開されていないAPIが必要な場合は、いくつかのリフレクションを行う必要がある場合があります. 所有しているいくつかのクラスをテストするためにそれを使用する人もいますが、テストのためだけに内部メンバーにアクセスできるようにインターフェイスを変更したくありません。

やるならちゃんとやれよ

  • 壊れやすい問題を軽減:

破損しやすい問題を軽減するには、継続的インテグレーション ビルドなどで実行される単体テストでテストすることにより、潜在的な破損を検出することをお勧めします。もちろん、これは常に同じアセンブリ (プライベート メンバーを含む) を使用することを意味します。動的なロードとリフレクションを使用する場合は、火遊びが好きですが、呼び出しが生成する可能性のある例外をいつでもキャッチできます。

  • リフレクションの遅さを軽減します。

.Net Framework の最近のバージョンでは、CreateDelegate は MethodInfo 呼び出しを 50 倍上回っています。

// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType, 
  BindingFlags.NonPublic | BindingFlags.Instance);

// Here we create a Func that targets the instance of type which has the 
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
                 typeof(Func<TInput, TOutput[]>), this);

draw呼び出しは、そのような標準としてMethodInfo.Invoke 使用するよりも約 50 倍高速になります。drawFunc

var res = draw(methodParams);

この投稿をチェックして、さまざまなメソッド呼び出しのベンチマークを確認してください

于 2017-04-20T03:48:55.997 に答える
2

描画したいタイプごとに異なるDrawメソッドを用意するだけではいけませんか?次に、オーバーロードされたDrawメソッドを呼び出して、描画するitemType型のオブジェクトを渡します。

あなたの質問は、itemTypeが本当に異なるタイプのオブジェクトを参照しているかどうかを明確にしません。

于 2008-09-27T11:12:33.553 に答える
1

BindingFlags.NonPublicメソッドの場所に渡すことができると思いますGetMethod

于 2008-09-25T19:28:52.997 に答える
0

これがどこに向かっているのか、そしてこのスレッドの何人かの人々が「まだ機能していない」と不平を言う理由を理解するために、この(補足)回答(それが回答である場合もあります)を読んでください

ここの回答の1つとまったく同じコードを書きました。しかし、私にはまだ問題がありました。ブレークポイントを配置しました

var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );

実行しましたが、mi == null

そして、関係するすべてのプロジェクトで「再構築」するまで、このような動作を続けました。リフレクションメソッドが3番目のアセンブリに座っている間に、1つのアセンブリをユニットテストしていました。まったく混乱しましたが、イミディエイト ウィンドウを使用してメソッドを発見したところ、単体テストを試みたプライベート メソッドの名前が古いことがわかりました (名前を変更しました)。これは、単体テスト プロジェクトがビルドされても、古いアセンブリまたは PDB がまだそこにあることを示しています。何らかの理由で、テスト プロジェクトがビルドされませんでした。「再構築」が機能しました

于 2018-05-23T05:06:57.757 に答える