70488


CやC++では、引数名 = 値のような出力処理を下記のようなマクロで定義ができ、  
引数を１つ渡すだけで呼び出すことができたと思います。

[code]

    #define  DPRINTF(x)  printf(#x " = %d\n", (x))
    
    DPRINTF(val0);
    DPRINTF(val1);
    
[/code]

一方、C#では言語仕様でマクロが使えないと聞いたのですが、上記のように  
引数を１つ渡すだけで引数名と値を表示できる処理は記述できるのでしょうか？

もしよい方法があれば、ご教授いただけると助かります。


CC BY-SA 4.0
2020-09-16T15:51:00.817
70457
2020-09-18T06:55:15.720
2020-09-17T00:43:39.577
2238
4260
question
c#
C#におけるマクロの代替方法につきまして


C#では呼び出し元の変数名を受け取ることはできません。  
従いまして、呼び出し側で、変数とその名前を引数で渡すことになると思います。  
変数の名前はnameof(xx)で取得することができます。

[code]

    DPRINTF(val0);
    
[/code]

は

[code]

    DPRINTF(val0, nameof(val0));
    
[/code]

みたいになると思います。


CC BY-SA 4.0
2020-09-17T01:09:02.923
70465
2020-09-17T01:09:02.923
24490
70457
answer


C#はオブジェクト指向を採用しているので、変数そのものを出力したいというシーンがあまりないように思います。  
重要な値であればクラスメンバーとして保持されているでしょうし、`ToString()`もしくは他のメソッドで表現できるようになっているべきです。クラス利用者側は適切なメソッドを呼ぶだけです。

* * *

それでも簡単な記述で変数名と値を取得するためのハックとしては[匿名型](https://docs.microsoft.com/ja-
jp/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types)があります。  
匿名型では本来 `new { name = value }` の形式で構築しますが、省略形式として `new { variable }`
があります。この場合 `nameof(variable)` がプロパティ名となります。  
匿名型の場合、 `,` 区切りで複数の値を指定することができる点と `ToString()` メソッドも適切に動作します。

[code]

    var i = 0;
    var s = "abc";
    
    Console.WriteLine(new { i, s }.ToString());
    // => { i = 0, s = abc }
    
[/code]


CC BY-SA 4.0
2020-09-17T09:33:42.610
70488
2020-09-17T22:11:02.210
2020-09-17T22:11:02.210
4236
4236
70457
answer


他の方がコメントされているように、`nameof`を使用するのが適切かと思います。

どうしても「引数を１つ渡すだけ」を実現したいのであれば、下記の様に式木を使用することもできます。  
実行効率が大変悪いので、(デバッグ目的と推察されるので)デバッグビルドでのみ実行されるようにしています。

[code]

    using System;
    using System.Linq.Expressions;
    
    public static class Program {
        public static void Main() {
            var val0 = "aaa";
            DbgPrint(() => val0);
        }
        [System.Diagnostics.Conditional("DEBUG")]
        public static void DbgPrint<T>(Expression<Func<T>> expression)
        {
            var name = ((MemberExpression)expression.Body).Member.Name;
            var value = expression.Compile().Invoke();
            Console.WriteLine($"{name} = {value}");
        }
    }
    
[/code]


CC BY-SA 4.0
2020-09-17T13:40:34.170
70497
2020-09-17T13:40:34.170
9113
70457
answer


現行のC#(8.0)ではできませんが、将来のC#(10.0以降)に提案されていますので情報として挙げておきます。

<https://github.com/dotnet/csharplang/issues/287>

[code]

    // NOTE: Maybe C# 10.0 or later
    public static class FooExtensions
    {
        public static void DbgPrint<T>(T value, [CallerArgumentExpression("value")] string name = null)
        {
            Console.WriteLine($"{name} = {value}");
        }
    }
    
    
    var a = 123;
    FooExtensions.DbgPrint(a); // "a = 123"
    
    
[/code]


CC BY-SA 4.0
2020-09-18T06:55:15.720
70513
2020-09-18T06:55:15.720
14817
70457
answer