TomoProgの技術書

底辺プログラマーが達人プログラマーになるまで

【C#】呼び出し元のメソッド名を渡したいときはCallerMemberNameAttributeが便利

皆さん
こんにちは、こんばんは
TomoProgです。

久しぶりのブログ投稿です。
最近はQiitaに書いていましたが、このブログも少しですが毎日の閲覧があるので、
このまま何も書かないはもったいない!
ということで、これからはこちらをメインに更新していこうかと考えています。

今回はC#CallerMemberNameAttributeを使うことで、
呼び出し元のメソッド名を簡単に渡せることを知ったため、
その方法について書こうと思います。

それでは頑張っていきましょう。

題材

以下のようなログメッセージと呼び出し元のメソッド名を出力するロガーを題材に CallerMemberNameAttributeを試していきます。

class Logger
{
    /// <summary>
    /// ファイルパス
    /// </summary>
    public string FilePath { get; private set; }
    public Logger(string filePath)
    {
        FilePath = filePath;
    }

    /// <summary>
    /// ログ出力
    /// </summary>
    /// <param name="msg">メッセージ</param>
    /// <param name="methodName">呼び出し元のメソッド名</param>
    public void Write(string msg, string methodName)
    {
        using (var sw = new StreamWriter(FilePath, true, Encoding.UTF8))
        {
            sw.WriteLine($"{msg} called by [{methodName}]");
        }
    }
}

CallerMemberNameAttributeを使わない場合

まずはCallerMemberNameAttributeを使わない場合を考えてみます。
メソッド名はSystem.Reflection.MethodBaseから取得できるため、そちらを使ってログを書いてみます。

class Program
{
    static Logger logger = new Logger("sample.log");

    static void Main(string[] args)
    {
        Method1();
        Method2();
    }

    static void Method1()
    {
        logger.Write("ログメッセージ1", MethodBase.GetCurrentMethod().Name);
    }

    static void Method2()
    {
        logger.Write("ログメッセージ2", MethodBase.GetCurrentMethod().Name);
    }
}

GetCurrentMethodメソッドは現在実行中のメソッドを表すMethodBaseオブジェクトを返します。
そのオブジェクトのNameプロパティにメソッド名が入っているため、それを利用します。

実行後のsample.logを確認すると

ログメッセージ1 called by [Method1]
ログメッセージ2 called by [Method2]

うまくログを書くことができました。

CallerMemberNameAttributeを使った場合

それでは次にCallerMemberNameAttributeを使って同じようにログを書いてみます。

Loggerクラス

class Logger
{
    // -- 省略 --

    /// <summary>
    /// ログ出力
    /// </summary>
    /// <param name="msg">メッセージ</param>
    /// <param name="methodName">呼び出し元のメソッド名</param>
    public void Write(string msg, [CallerMemberName]string methodName = null)
    {
        using (var sw = new StreamWriter(FilePath, true, Encoding.UTF8))
        {
            sw.WriteLine($"{msg} called by [{methodName}]");
        }
    }
}

Main

class Program
{
    // -- 省略 --

    static void Method1()
    {
        logger.Write("ログメッセージ1");
    }

    static void Method2()
    {
        logger.Write("ログメッセージ2");
    }
}

LoggerクラスのWriteメソッドのmethodName引数にCallerMemberNameAttributeを追加しました。
また、呼び出し側の第2引数を削除しました。

実行後のsample.logを確認すると

ログメッセージ1 called by [Method1]
ログメッセージ2 called by [Method2]

CallerMemberNameAttributeを使わないときと同じログを書くことができました。

このように、CallerMemberNameAttributeを使うと逐一メソッド名を渡さずとも、メソッド名を受け取る事ができるため便利です。
ちなみに第2引数はデフォルト引数のため、メソッド名を渡してあげることもできます。

まとめ

CallerMemberNameAttributeを使うとメソッド名を渡さずともメソッド名を受け取る事ができる

今回のようなログ出力を自作するときなんかに使えそうかなと思います。

それではまた。

TomoProg