web-dev-qa-db-ja.com

例外の原因となったメソッドの名前を取得する方法

私のコードは次のようになります。

try
{
    _productRepo.GetAllProductCategories();
}
catch (Exception ex)
{
    //Do Something
}

メソッド名を表示する方法が必要です。上記の場合、GetAllProductCategories()メソッドで例外がスローされた場合、結果としてこのメ​​ソッド名、つまり「GetAllProductCategories()」を取得する必要があります。誰かが私にこれを行う方法を提案できますか?

17
SKumar

System.Exceptionには TargetSite プロパティがあり便利です。

現在の例外をスローするメソッドを取得します。

あなたの場合、あなたはおそらく次のようなものが欲しいでしょう:

catch (Exception ex)
{
   MethodBase site = ex.TargetSite;
   string methodName = site == null ? null : site.Name;
   ...           
}

リストされている問題のいくつかを指摘する価値があります。

この例外をスローするメソッドが使用できず、スタックトレースがnull参照ではない場合(Visual BasicではNothing)、TargetSiteはスタックトレースからメソッドを取得します。スタックトレースがnull参照の場合、TargetSiteもnull参照を返します。

注:例外ハンドラーがアプリケーションドメインの境界を越えて例外を処理する場合、TargetSiteプロパティは例外がスローされたメソッドの名前を正確に報告しない場合があります。

@leppieが示唆するようにStackTraceプロパティを使用することもできますが、これはスタック上のフレームの文字列表現であることに注意してください。したがって、実行をスローしたメソッドのnameのみが必要な場合は、操作する必要があります。

21
Ani

StackFrameにあります...

private string GetExecutingMethodName()
{
    string result = "Unknown";
    StackTrace trace = new StackTrace(false);
    Type type = this.GetType();

    for (int index = 0; index < trace.FrameCount; ++index)
    {
        StackFrame frame = trace.GetFrame(index);
        MethodBase method = frame.GetMethod();

        if (method.DeclaringType != type && !type.IsAssignableFrom(method.DeclaringType))
        {
            result = string.Concat(method.DeclaringType.FullName, ".", method.Name);
            break;
        }
    }

    return result;
}

このメソッドはLoggingハンドラークラス用に作成されており、GetType()を使用すると、Loggingハンドラークラス内のメソッドが最後に実行されたメソッドとして返されることがなくなります。 Loggingハンドラークラスは単なるログ例外以外の目的で作成されているため、新しいStackTraceオブジェクトが必要でした。明らかに、「例外をスローしたメソッド」を見つけるためにGetType()は必要ないかもしれません。

スタックの最上位が必要な場合は、最初のフレームを取得し、GetMethod()を呼び出してそれを返すか、単にTargetSiteを使用します。その後、GetType()を削除できます。また、StackTraceオブジェクトを作成するには、Exceptionを渡す必要があることに注意してください。例えば:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Test();
        }
        catch (Exception ex)
        {

            // does not work properly - writes "Main"
            Console.WriteLine(MethodBase.GetCurrentMethod());

            // properly writes "TestConsole.Program.Test"
            Console.WriteLine(GetExecutingMethodName(ex));

            // properly writes "Test"
            Console.WriteLine(ex.TargetSite.Name);
        }

        Console.ReadKey();
    }


    static void Test()
    {
        throw new Exception("test");
    }

    private static string GetExecutingMethodName(Exception exception)
    {
        var trace = new StackTrace(exception);
        var frame = trace.GetFrame(0);
        var method = frame.GetMethod();

        return string.Concat(method.DeclaringType.FullName, ".", method.Name);
    }
}

基本的に、TargetSite()が必要なことを実行する場合は、それ以上先に進みません。ただし、Loggingハンドラーでは、例外オブジェクトを使用できないことがよくあります(つまり、トレースと監査)。そのため、最後に実行されたメソッド、つまりLoggingメソッドの前のメソッドを取得するには新しいStackTrace()オブジェクトが必要です。

3
Chris Gessler

スタックトレースを見てください。

それは例外のプロパティです。

1
leppie