Поиск имени переменной, переданной функции

Позвольте мне использовать следующий пример, чтобы объяснить мой вопрос:

public string ExampleFunction(string Variable) { return something; } string WhatIsMyName = "Hello World"'; string Hello = ExampleFunction(WhatIsMyName); 

Когда я передаю переменную «WhatIsMyName» в функцию example, я хочу иметь возможность получить строку исходного имени переменной. Возможно, что-то вроде:

 Variable.OriginalName.ToString() 

Есть какой-либо способ сделать это?

** Нет. ** Я так не думаю.

Имя переменной, которое вы используете, предназначено для вашего удобства и удобочитаемости. Компилятор не нуждается в этом и просто вытаскивает его, если я не ошибаюсь.

Если это помогает, вы можете определить новый class с именем NamedParameter с атрибутами Name и Param. Затем вы передаете этот объект в качестве параметров.

То, что вы хотите, невозможно напрямую, но вы можете использовать выражения в C # 3.0:

 public void ExampleFunction(Expression> f) { Console.WriteLine((f.Body as MemberExpression).Member.Name); } ExampleFunction(x => WhatIsMyName); 

Обратите внимание, что это зависит от неуказанного поведения и, хотя оно работает в текущих компиляторах Microsoft C # и VB, а также в компиляторе Mono C #, нет гарантии, что это не остановит работу в будущих версиях.

Я знаю, что это старый вопрос, но в C # 6.0 они вводят имя оператора, которое должно решить эту проблему. Имя оператора разрешает имя переменной, переданной в нее.

Использование для вашего дела будет выглядеть так:

 public string ExampleFunction(string variableName) { //Construct your log statement using c# 6.0 string interpolation return $"Error occurred in {variableName}"; } string WhatIsMyName = "Hello World"'; string Hello = ExampleFunction(nameof(WhatIsMyName)); 

Главное преимущество заключается в том, что это делается во время компиляции,

Имя выражения является константой. Во всех случаях имяof (…) оценивается во время компиляции для создания строки. Его аргумент не оценивается во время выполнения и считается недостижимым кодом (однако он не выдает предупреждение «недостижимый код»).

Более подробную информацию можно найти здесь

Старая версия C 3.0 и выше
Настроить на Nawfals ответ

 GetParameterName2(new { variable }); //Hack to assure compiler warning is generated specifying this method calling conventions [Obsolete("Note you must use a single parametered AnonymousType When Calling this method")] public static string GetParameterName(T item) where T : class { if (item == null) return string.Empty; return typeof(T).GetProperties()[0].Name; } 
 static void Main(string[] args) { Console.WriteLine("Name is '{0}'", GetName(new {args})); Console.ReadLine(); } static string GetName(T item) where T : class { var properties = typeof(T).GetProperties(); Enforce.That(properties.Length == 1); return properties[0].Name; } 

Более подробная информация содержится в этом сообщении в блоге .

Три способа:

1) Что-то без отражения вообще:

 GetParameterName1(new { variable }); public static string GetParameterName1(T item) where T : class { if (item == null) return string.Empty; return item.ToString().TrimStart('{').TrimEnd('}').Split('=')[0].Trim(); } 

2) Использует reflection, но это намного быстрее, чем другие два.

 GetParameterName2(new { variable }); public static string GetParameterName2(T item) where T : class { if (item == null) return string.Empty; return typeof(T).GetProperties()[0].Name; } 

3) Самый медленный из всех, не используйте.

 GetParameterName3(() => variable); public static string GetParameterName3(Expression> expr) { if (expr == null) return string.Empty; return ((MemberExpression)expr.Body).Member.Name; } 

Чтобы получить имя и значение параметра combo, вы можете расширить эти методы. Конечно, его легко получить значение, если вы передадите параметр отдельно в качестве другого аргумента, но это неэлегантно. Вместо:

1)

 public static string GetParameterInfo1(T item) where T : class { if (item == null) return string.Empty; var param = item.ToString().TrimStart('{').TrimEnd('}').Split('='); return "Parameter: '" + param[0].Trim() + "' = " + param[1].Trim(); } 

2)

 public static string GetParameterInfo2(T item) where T : class { if (item == null) return string.Empty; var param = typeof(T).GetProperties()[0]; return "Parameter: '" + param.Name + "' = " + param.GetValue(item, null); } 

3)

 public static string GetParameterInfo3(Expression> expr) { if (expr == null) return string.Empty; var param = (MemberExpression)expr.Body; return "Parameter: '" + param.Member.Name + "' = " + ((FieldInfo)param.Member).GetValue(((ConstantExpression)param.Expression).Value); } 

1 и 2 теперь сопоставимы, 3 снова вяло.

Нет, но всякий раз, когда вы обнаруживаете, что занимаетесь такими сложными вещами, вы можете подумать о своем решении. Помните, что код должен быть легче читать, чем писать.

Да! Возможно. Я давно искал решение этой проблемы и, наконец, придумал взломать ее (это немного противно). Я бы не рекомендовал использовать это как часть вашей программы, и я думаю, что он работает в режиме отладки. Для меня это не имеет значения, поскольку я использую его только как инструмент отладки в моем classе консоли, чтобы я мог:

 int testVar = 1; bool testBoolVar = True; myConsole.Writeline(testVar); myConsole.Writeline(testBoolVar); 

вывод на консоль будет:

 testVar: 1 testBoolVar: True 

Вот функция, которую я использую для этого (не включая код упаковки для моего classа консоли.

  public Dictionary nameOfAlreadyAcessed = new Dictionary(); public string nameOf(object obj, int level = 1) { StackFrame stackFrame = new StackTrace(true).GetFrame(level); string fileName = stackFrame.GetFileName(); int lineNumber = stackFrame.GetFileLineNumber(); string uniqueId = fileName + lineNumber; if (nameOfAlreadyAcessed.ContainsKey(uniqueId)) return nameOfAlreadyAcessed[uniqueId]; else { System.IO.StreamReader file = new System.IO.StreamReader(fileName); for (int i = 0; i < lineNumber - 1; i++) file.ReadLine(); string varName = file.ReadLine().Split(new char[] { '(', ')' })[1]; nameOfAlreadyAcessed.Add(uniqueId, varName); return varName; } } 

System.Environment.StackTrace предоставит вам строку, которая включает текущий стек вызовов. Вы можете разобрать это, чтобы получить информацию, которая включает имена переменных для каждого вызова.

Хорошо Попробуйте этот class Utility,

 public static class Utility { public static Tuple GetNameAndValue(Expression> sourceExpression) { Tuple result = null; Type type = typeof (TSource); Func> process = delegate(MemberExpression memberExpression) { ConstantExpression constantExpression = (ConstantExpression)memberExpression.Expression; var name = memberExpression.Member.Name; var value = ((FieldInfo)memberExpression.Member).GetValue(constantExpression.Value); return new Tuple(name, (TSource) value); }; Expression exception = sourceExpression.Body; if (exception is MemberExpression) { result = process((MemberExpression)sourceExpression.Body); } else if (exception is UnaryExpression) { UnaryExpression unaryExpression = (UnaryExpression)sourceExpression.Body; result = process((MemberExpression)unaryExpression.Operand); } else { throw new Exception("Expression type unknown."); } return result; } } 

И пользователю нравится

  /*ToDo : Test Result*/ static void Main(string[] args) { /*Test : primivit types*/ long maxNumber = 123123; Tuple longVariable = Utility.GetNameAndValue(() => maxNumber); string longVariableName = longVariable.Item1; long longVariableValue = longVariable.Item2; /*Test : user define types*/ Person aPerson = new Person() { Id = "123", Name = "Roy" }; Tuple personVariable = Utility.GetNameAndValue(() => aPerson); string personVariableName = personVariable.Item1; Person personVariableValue = personVariable.Item2; /*Test : anonymous types*/ var ann = new { Id = "123", Name = "Roy" }; var annVariable = Utility.GetNameAndValue(() => ann); string annVariableName = annVariable.Item1; var annVariableValue = annVariable.Item2; /*Test : Enum tyoes*/ Active isActive = Active.Yes; Tuple isActiveVariable = Utility.GetNameAndValue(() => isActive); string isActiveVariableName = isActiveVariable.Item1; Active isActiveVariableValue = isActiveVariable.Item2; } 

Нет. Ссылка на вашу строковую переменную передается в funcion – в нее нет встроенной метадаеты. Даже reflection не вывело бы вас из леса здесь – работа назад от одного ссылочного типа не дает вам достаточно информации, чтобы делать то, что вам нужно.

Лучше вернитесь на чертежную доску на этом!

Р.П.

Вы можете использовать reflection, чтобы получить все свойства объекта, а не цитировать его, и получить значение свойства, в котором имя (свойства) соответствует переданному параметру.

Спасибо за все ответы. Думаю, мне просто нужно пойти с тем, что я сейчас делаю.

Для тех, кто хотел знать, почему я задал вышеуказанный вопрос. У меня есть следующая функция:

 string sMessages(ArrayList aMessages, String sType) { string sReturn = String.Empty; if (aMessages.Count > 0) { sReturn += "

"; for (int i = 0; i < aMessages.Count; i++) { sReturn += aMessages[i] + "
"; } sReturn += "

"; } return sReturn; }

Я отправляю ему массив сообщений об ошибках и class css, который затем возвращается как строка для веб-страницы.

Каждый раз, когда я вызываю эту функцию, я должен определить sType. Что-то вроде:

 output += sMessages(aErrors, "errors"); 

Как вы можете видеть, мои переменные называются aErrors, а мой class css называется ошибками. Я надеялся, что мой холод может понять, какой class использовать на основе имени переменной, которое я ему отправил.

Опять же, спасибо за все ответы.

GateKiller, что случилось с моим обходным решением? Вы можете переписать свою функцию тривиально, чтобы использовать ее (я взял на себя смелость улучшить функцию «на лету»):

 static string sMessages(Expression>> aMessages) { var messages = aMessages.Compile()(); if (messages.Count == 0) { return ""; } StringBuilder ret = new StringBuilder(); string sType = ((MemberExpression)aMessages.Body).Member.Name; ret.AppendFormat("

", sType); foreach (string msg in messages) { ret.Append(msg); ret.Append("
"); } ret.Append("

"); return ret.ToString(); }

Назовите это так:

 var errors = new List() { "Hi", "foo" }; var ret = sMessages(() => errors); 

Сделай это

 var myVariable = 123; myVariable.Named(() => myVariable); var name = myVariable.Name(); // use name how you like 

или именование в коде вручную

 var myVariable = 123.Named("my variable"); var name = myVariable.Name(); 

используя этот class

 public static class ObjectInstanceExtensions { private static Dictionary namedInstances = new Dictionary(); public static void Named(this T instance, Expression> expressionContainingOnlyYourInstance) { var name = ((MemberExpression)expressionContainingOnlyYourInstance.Body).Member.Name; instance.Named(name); } public static T Named(this T instance, string named) { if (namedInstances.ContainsKey(instance)) namedInstances[instance] = named; else namedInstances.Add(instance, named); return instance; } public static string Name(this T instance) { if (namedInstances.ContainsKey(instance)) return namedInstances[instance]; throw new NotImplementedException("object has not been named"); } } 

Код протестирован и самый элегантный, который я могу придумать.

Короткий ответ – нет … если вы действительно не мотивированы.

Единственный способ сделать это – через reflection и стекирование. Вам нужно будет получить фрейм стека, выработать местонахождение в вызывающей функции, из которой вы вызывается, а затем с помощью CodeDOM попытаться найти нужную часть дерева, чтобы узнать, что это за выражение.

Например, что если вызов был ExampleFunction (“a” + “b”)?

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

  • Формат строкового формата
  • Как скомпилировать 64-битное приложение с помощью Visual C ++ 2010 Express?
  • ToggleButton в C # WinForms
  • В этом конкретном случае существует ли разница между использованием списка инициализаторов членов и назначением значений в конструкторе?
  • Kendo UI datepicker несовместим с Chrome 56
  • Почему 0 <-0x80000000?
  • Как конвертировать CString и :: std :: string :: std :: wstring друг к другу?
  • Комбинация смешанного режима построена против версии 'v1.1.4322'
  • Ошибка сегментации перед основным
  • конвертировать список объектов из одного типа в другой, используя выражение lambda
  • Игнорировать отображение одного свойства с помощью Automapper
  • Interesting Posts

    Не удается получить доступ к виртуальной машине через ping с физической хост-машины

    Regexp распознавание адреса электронной почты трудно?

    Почему конверсия туда и обратно с помощью строки, небезопасной для двойной?

    Высокое среднее время отклика с жесткого диска

    Как увеличить количество отображаемых строк дампа трассировки Java-стека?

    Как генерировать AST из исходного кода Java?

    Как вы получаете свой общедоступный IP-адрес через командную строку Windows?

    Как отформатировать число 0..9 для отображения с двумя цифрами (это НЕ дата)

    java.net.UnknownHostException: Невозможно разрешить хост «»: нет адреса, связанного с именем хоста, и Конец ввода с символом 0

    Как получить доступ к зашифрованному BitLocker приводу в Linux?

    Ошибка сборки Xcode «Неопределенные символы для архитектуры x86_64»

    найти vs find_by vs где

    Показывать номер строки в обработке исключений

    Отключите всю конфигурацию, связанную с базой данных, в Spring Boot

    Есть ли ярлык, чтобы сделать комментарий блока в Xcode?

    Давайте будем гением компьютера.