вывести имя переменной в С#

у меня есть заявление

int A = 10,B=6,C=5;

и я хочу написать функцию печати, чтобы я передал ей переменную int, и она печатает мне имя переменной и значение.

например, если я вызываю print(A), он должен вернуть "A: 10", а print (B) должен вернуть "B:6"

Короче говоря, я хочу знать, как я могу получить доступ к имени переменной и напечатать его в строку в С#. Должен ли я использовать отражение?

После прочтения ответов

Привет всем, спасибо за предоставленные предложения. Я попробую их, однако я хотел знать, возможно ли это вообще в .NET 2.0? Ничего похожего на

#define prt(x) std::cout << #x " = '" << x << "'" << std::endl;

макрос, который есть в C/C++?


person Anirudh Goel    schedule 08.04.2009    source источник


Ответы (6)


Единственный разумный способ сделать это — использовать Expression API; но это еще больше меняет код...

static void Main() {
    int A = 10, B = 6, C = 5;
    Print(() => A);
}
static void Print<T>(Expression<Func<T>> expression) {
    Console.WriteLine("{0}={1}",
        ((MemberExpression)expression.Body).Member.Name,
        expression.Compile()());
}

Примечание: если это делается для целей отладки, обязательно добавьте [Conditional("DEBUG")] к методу, так как использование переменной таким образом незаметно изменяет природу кода.

person Marc Gravell    schedule 08.04.2009
comment
Ух ты. Это круто. Отличная работа. - person Brian Genisio; 08.04.2009
comment
Привет, Марк, ничего похожего на #define prt(x) std::cout ‹‹ #x = ' ‹‹ x ‹‹ ' ‹‹ std::endl; есть на С#? - person Anirudh Goel; 09.04.2009

Вы можете использовать лямбда-выражения:

static void Main( string[] args ) {
    int A = 50, B = 30, C = 17;
    Print( () => A );
    Print( () => B );
    Print( () => C );
}

static void Print<T>( System.Linq.Expressions.Expression<Func<T>> input ) {
    System.Linq.Expressions.LambdaExpression lambda = (System.Linq.Expressions.LambdaExpression)input;
    System.Linq.Expressions.MemberExpression member = (System.Linq.Expressions.MemberExpression)lambda.Body;

    var result = input.Compile()();
    Console.WriteLine( "{0}: {1}", member.Member.Name, result );
}
person TcKs    schedule 08.04.2009

Это невозможно без некоторой «помощи» с места вызова; даже рефлексия не знает об именах локальных переменных.

person Brian    schedule 08.04.2009
comment
Это возможно в C# 3.0 и лямбда-выражениях. - person TcKs; 08.04.2009
comment
@TcKs: Строго говоря, ему нужен .NET 3.5, а также C # 3.0. - person Marc Gravell; 08.04.2009
comment
В вопросе написано print(A) - это невозможно. - person Brian; 08.04.2009

Это невозможно сделать с отражением (см. Брайан и Джоэл). В общем случае это невозможно просто потому, что вы не можете гарантировать, что именованное значение будет передано вашей функции печати. Например, я мог бы так же легко сделать следующее

print(42);
print(A + 42);

Ни одно из этих выражений на самом деле не имеет имени. Что вы ожидаете напечатать здесь?

person JaredPar    schedule 08.04.2009
comment
Думаю, предполагается, что в функцию будет передано имя переменной, так как программой будет пользоваться сам пользователь. Хотя ход твоих мыслей правильный. Это просто мой POV. - person Anirudh Goel; 09.04.2009

Другое решение (из закрытого сообщения):

Вдохновлено Джона Скита. сообщение об обработке исключений Null Reference и внезапное напоминание о проекции, есть способ сделать это.

Вот полный рабочий кодез:

public static class ObjectExtensions {
    public static string GetVariableName<T>(this T obj) {
        System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();

        if(objGetTypeGetProperties.Length == 1)
            return objGetTypeGetProperties[0].Name;
        else
            throw new ArgumentException("object must contain one property");
    }
}

class Program {
    static void Main(string[] args) {
        string strName = "sdsd";
        Console.WriteLine(new {strName}.GetVariableName());

        int intName = 2343;
        Console.WriteLine(new { intName }.GetVariableName());
    }
}
person Igor Zevaka    schedule 10.12.2009
comment
Это делает вопрос вполне выполнимым. Просто добавьте метод с именем prt(object obj), который затем вызывает новый {obj}.GVN(); метод. - person mikeschuld; 02.02.2010

Если вам нужно поддерживать больше типов, чем int, используйте Expression API, но избегайте обобщений и изящно обрабатывайте разные выражения:

private static string ToDebugOutput(params Expression<Func<object>>[] variables)
{
    var sb = new StringBuilder();
    foreach (var input in variables)
    {
        string name;
        if (input.Body is UnaryExpression unary && unary.Operand is MemberExpression operand)
        {
            name = operand.Member.Name;
        }
        else if (input.Body is MemberExpression member)
        {
            name = member.Member.Name;
        }
        else
        {
            throw new NotSupportedException($"typeof lambda: {input.Body.GetType()}");
        }

        var result = input.Compile()();
        sb.Append($"{name}={result}, ");
    }

    return sb.ToString();
}

Использование:

string s = "123";
double d = 1.23;
int i2 = 123;
var out2 = ToDebugOutput(() => s, () => d, () => i2);
// out2 = "s=123, d=1.23, i2=123, "
person Jack Miller    schedule 20.04.2021