web-dev-qa-db-ja.com

呼び出し元のメソッドのパラメーターの値を取得するにはどうすればよいですか?

質問

クラスに呼び出されたメソッドからパラメーターのvaluesを取得できるようにする必要があるコードを書いています。 ParameterInfo []配列に到達する方法は知っていますが、値を取得する方法がわかりません。これも可能ですか?

もしそうなら、それはMethodInfoオブジェクトからMethodBodyプロパティを使用することと関係があると思います。これにより、プロパティを含むILストリームを検査できますが、その方法がわからず、見つかりませんでした。 Googleの該当するコード。

コード

// Finds calling method from class that called into this one
public class SomeClass
{
    public static void FindMethod()
    {
        for (int i = 1; i < frameCount; i++)
        {
            var frame = new StackFrame(i);
            var methodInfo = frame.GetMethod();
            if (methodInfo.DeclaringType != this.GetType())
            {
                string methodName = frame.GetMethod().Name;
                var paramInfos = methodInfo.GetParameters();

                // Now what?? How do I get the values from the paramInfos

                break;
            }
            else if (i == frameCount - 1)
            {
                throw new TransportException("Couldn't find method name");
            }
        }
    }
}
21
Chris Benard

スタックを自分でイントロスペクトせずにそれを行うことはできません(多くの最適化はスタックフレームが期待したものではないことを意味する可能性があるため、または渡されたパラメーターが実際にはメソッド署名が示唆するものではないことを意味する可能性があるため、これは脆弱です(オブジェクト/構造体のサブフィールドのみを使用していることを検出し、代わりにそれを渡すための最適化JITコンパイラー)。

ParameterInfoは、渡された値ではなく、コンパイルされたメソッドのsignatureを通知するだけです。

これを自動的に実現する唯一の現実的な方法は、コードインジェクション(AOPなど)を使用してデータを作成し、ILの分析に基づいてデータを使用して必要な処理を実行することです。

これは一般的には良い考えではありません。何かをデバッグする必要がある場合はデバッガーを使用し、何かをログに記録する必要がある場合は、ログに記録している内容について明示的にしてください。

明確にするために単純な反射技術できない完全な一般性であなたが望むものを達成する

19
ShuggyCoUk

MicrosoftのJonathanKeljoは、 このニュースグループの投稿 、:

残念ながら、今日のコールスタックから引数情報を取得する簡単な方法は、デバッガーを使用することだけです。アプリケーションのエラーログインの一部としてこれを実行しようとしていて、エラーログをサポート部門に返送する予定の場合は、将来、その目的でミニダンプを使用してもらうことを望んでいます。 (今日、マネージコードでミニダンプを使用すると、デフォルトでスタックトレースを取得するのに十分な情報が含まれていないため、少し問題があります。ヒープ付きのミニダンプの方が優れていますが、意味がわかれば「ミニ」ではありません。)

純粋主義者は、人々がコールスタックの他の場所の関数から引数を取得できるコードを書くことを許可すると、カプセル化を破り、変更に直面しても非常に壊れやすいコードを作成するように促されると言うでしょう。 (シナリオにはこの特定の問題はありませんが、この機能に対する他の要求を聞いたことがあります。とにかく、これらの要求のほとんどは、スレッドストアを使用するなど、他の方法で解決できます。)ただし、さらに重要なのは、セキュリティに影響があることです。このうち、プラグインを許可するアプリケーションは、それらのプラグインが機密情報のためにスタックをスクレイピングするリスクがあります。この関数を完全な信頼が必要であるとマークすることはできますが、それでは、私が聞いたほとんどすべてのシナリオで使用できなくなります。

ジョナサン

だから...簡単な答えは「できない」だと思います。それは最悪だ。

5
Chris Benard

はい、できます。

あなたがする必要があるのは、IL逆アセンブラ(System.Reflection.Emit名前空間内で達成可能)を使用して、探しているパラメータ値を含むオペランドを見つけることです。

これから始めますSO質問: C#リフレクションとすべての参照の検索

次に、回答に記載されているクラス(Mono.Reflectionから)を使用して検査を行います。このようなもの:

            var instructions = method.GetInstructions();
            foreach (var instruction in instructions)
            {
                var methodInfo = instruction.Operand as MethodInfo;
                if(methodInfo == null)
                {
                    continue;
                }
                if (instruction.OpCode.Name.Equals("call") && methodInfo.Name.Equals("YourMethodHere"))
                {
                    var value = (CastToMyType)instruction.Previous.Operand;
                    // Now you have the value...
                }
            }
4
Daniel Crenna

StackFrameまたはStackTraceのどちらでもそれを行うことはできません。ただし、パラメーター値を取得できるように、いくつかのインターセプトフレームワーク(Spring.NETのAOPなど)を使用できます。

1
Anton Gogolev

ここを参照してください:

C#でスタック上の変数のリストを取得できますか?

そこにある私の答えに対するすべてのコメントに基づいて、それは可能ではないと思います。 PropertyInfoクラスにはGetValueメソッドがありますが、そのためには、値を取得する実際のオブジェクトが必要です。

0
BFree