Qikuzou
@Qikuzou

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

c#で変数名を完全な文字列に変換したい

解決したいこと

c#で変数名を完全な文字列に変換したいのですが、nameofだと期待する結果になりません。

発生している問題・エラー

実際の結果

nameof(aaa) -> aaa
nameof(aaa.bbb) -> bbb
nameof(aaa.bbb.ccc) -> ccc

期待する結果

nameof(aaa) -> aaa
nameof(aaa.bbb) -> aaa.bbb
nameof(aaa.bbb.ccc) -> aaa.bbb.ccc

該当するソースコード

public class AAA
{
    public class BBB
    {
        public int ccc;
    }

    public BBB bbb;
}

void Example()
{
    var aaa = new AAA();
    Debug.WriteLine($"nameof(aaa) -> {nameof(aaa)}");
    Debug.WriteLine($"nameof(aaa.bbb) -> {nameof(aaa.bbb)}");
    Debug.WriteLine($"nameof(aaa.bbb.ccc) -> {nameof(aaa.bbb.ccc)}");
}

以下のようにすれば期待する結果にはなりますが、面倒ですし汎用性がありません。

void Example()
{
    var aaa = new AAA();
    Debug.WriteLine($"nameof(aaa) -> {nameof(aaa)}");
    Debug.WriteLine($"nameof(aaa.bbb) -> {nameof(aaa)}.{nameof(aaa.bbb)}");
    Debug.WriteLine($"nameof(aaa.bbb.ccc) -> {nameof(aaa)}.{nameof(aaa.bbb)}.{nameof(aaa.bbb.ccc)}");
}

シンプルな記述で変数名を完全な文字列に変換する方法はないでしょうか?

0

2Answer

公式で issues が 幾つか上がっている話ですね。

コメントにある様にこの様な手もあります。

I feel uneasy promoting my own framework here, but I made something for this a long time ago. It isn't perfect, but it will handle many common cases. You can call:

ExpressionHelper.GetText(() => myVariable.MyList[i].MyProperty);

And get "myVariable.MyList[i].MyProperty" out.

It won't cover full type names, though. I had something for that too, but I never ported it to my current code base.

ただ、今だともっと簡単な方法として .NET 6 で導入された CallerArgumentExpressionAttribute が使えます。

つまり、次の様な感じでもいいかもしれません。

using System;
using System.Runtime.CompilerServices;

Example1 v1 = new ();
string[] v2 = ["1", "2", "3"];
string? v3 = null;
Console.WriteLine(GetFullName(v1.Value));
Console.WriteLine(GetFullName(v2[2].EndsWith("3")));
Console.WriteLine(GetFullName(v3?.ToLower()));

static string GetFullName<T>(T any, [CallerArgumentExpression(nameof(any))] string expression = null!)
{
    return expression;
}

class Example1 {
    public string Value {get;set;}
}
output
v1.Value
v2[2].EndsWith("3")
v3?.ToLower()

ただ、 nameof() の様に コンパイル時に定数化されるというアプローチではないことに考慮が必要です。(実行してしまうのでエラーにもなりえます

追伸:

拡張関数にしてしまって次の様にしてもいいかもしれません。

using System;
using System.Runtime.CompilerServices;

Example1 v1 = new ();
string[] v2 = ["1", "2", "3"];
string? v3 = null;
Console.WriteLine(v1.Value.GetFullName());
Console.WriteLine(v2[2].EndsWith("3").GetFullName());
Console.WriteLine((v3?.ToLower()).GetFullName());

class Example1 {
    public string? Value {get;set;}
}

static class FullnameExtensions {
    public static string GetFullName<T>(this T _, [CallerArgumentExpression(nameof(_))] string expression = null)
    {
        return expression;
    }
}

3Like

Comments

  1. @Qikuzou

    Questioner

    CallerArgumentExpressionを使うとbbbがnullのときに例外が発生してしまいますが、ちゃんと初期化しておけばいいじゃないという話なので公式で実装されるまではCallerArgumentExpressionを使うものでいこうと思います。
    ご回答ありがとうございました。

Your answer might help someone💌