22

質問

クラスに呼び出されたメソッドからパラメーターのを取得できるようにする必要があるコードをいくつか書いています。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");
            }
        }
    }
}
4

6 に答える 6

19

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

ParameterInfo は、渡された値ではなく、コンパイルされたメソッドのシグネチャを示すだけです。

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

何かをデバッグする必要がある場合はデバッガを使用し、何かをログに記録する必要がある場合は、ログに記録しているものを明示する必要があります。

明確にするために、単純なリフレクティブ手法では、完全な一般性で望むものを達成することはできません

于 2009-01-29T17:41:59.003 に答える
5

Microsoft の Jonathan Keljo は、このニュース グループの投稿で次のように述べています。

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

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

ジョナサン

だから... 短い答えは「できません」だと思います。それはひどい。

于 2009-01-29T17:40:48.397 に答える
5

はい、できます。

必要なのは、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...
                }
            }
于 2011-05-22T18:25:12.390 に答える
1

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

于 2009-01-29T17:33:31.953 に答える
0

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

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

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

于 2009-01-29T17:43:02.853 に答える
0

これが解決策としてカウントされるかどうかはわかりませんが、私が持っていた特定のケースでうまくいきました。フロートが最小限のコード変更で変更されるたびにログに記録したかったのですが、

パラメータを把握するためにスタック トレース ラインでファイルを読み取る

public static Score operator +(Score x,float y) {
    var st = new StackTrace(true);
    var sf = st.GetFrame(1);                
    string paramName = File.ReadLines(sf.GetFileName()).ElementAtOrDefault(sf.GetFileLineNumber()-1).Split(new[] { "+=" }, StringSplitOptions.None)[1];
            
    x.DebugString += (paramName+" "+y);
    x.DebugString += System.Environment.NewLine;
            
    x.val += y;
    return x;
}
            
            
void Main(){
    Score score = new Score();
    float firstScore = 2;
    float secondScore = -13;
    score+=firstScore;
    score+=secondScore;
    Console.WriteLine(score.DebugString);
}
        
Output : 
firstscore  2
secondScore -13
于 2020-09-07T19:50:57.860 に答える