Вывести имя переменной в C#
У меня есть заявление
int A = 10,B=6,C=5;
и я хочу написать функцию печати так, чтобы я передал ей переменную int, и она напечатает мне имя переменной и значение.
Например, если я вызываю print(A), он должен вернуть "A: 10", а print (B), тогда он должен вернуть "B:6"
Короче говоря, я хочу знать, как я могу получить доступ к имени переменной и распечатать его в строку в C#. Должен ли я использовать отражение?
Прочитав ответы
Привет всем, спасибо за предоставленные предложения. Я попробую их, однако я хотел знать, возможно ли это в.NET 2.0? Ничего похожего на
#define prt(x) std::cout << #x " = '" << x << "'" << std::endl;
макрос, который есть в C/C++?
7 ответов
Единственный разумный способ сделать это - использовать 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")]
к методу, поскольку использование переменной таким образом изменяет природу кода тонкими способами.
Вы можете использовать лямбда-выражения:
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 );
}
Это невозможно без некоторой "помощи" с сайта вызова; даже отражение не знает об именах локальных переменных.
Это невозможно сделать с отражением (см. Брайан и Джоэл). В общем, это невозможно просто потому, что вы не можете гарантировать, что именованное значение передается вашей функции печати. Например, я мог бы так же легко сделать следующее
print(42);
print(A + 42);
Ни одно из этих выражений на самом деле не имеет имени. Что бы вы ожидали напечатать здесь?
Другое решение (из закрытого поста):
Вдохновленный постом Джона Скита об обработке исключений 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());
}
}
Если вам нужно поддерживать больше типов, чем
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, "