Получить переменное (не жестко запрограммированное) имя?
Я ищу способ получить имя переменной, поэтому мне не нужно использовать жестко запрограммированные объявления при необходимости (имена свойств и т.д.):
Я не верю, что это возможно; возможно, у кого-то есть решение.
Примечание: даже не переменные, свойства также будут перемещаться.
'Pseudo:
Module Module1
Sub Main()
Dim variable = "asdf"
Dim contact As New Contact
Dim v1 = GetVariableName(variable) 'returns variable
Dim v2 = GetVariableName(contact.Name) 'returns Name
End Sub
Class Contact
Public ReadOnly Property Name()
Get
Return Nothing
End Get
End Property
End Class
Public Function GetVariableName(variable As Object) As String
':}
End Function
End Module
Ответы приветствуются в VB или С#.
Ответы
Ответ 1
О, есть простое решение, использование деревьев выражений здесь является примером, просто приспосабливайтесь к вашим потребностям в С#
string GetPropertyName<T>(Expression<Func<T>> property)
{
MemberExpression ex = (MemberExpression)property.Body;
string propertyName = ex.Member.Name;
return propertyName;
}
Теперь вы можете сделать
String example = null;
String propertyName = GetPropertyName(()=>example.Length);
//propertyName == "Length"
В первый раз, когда я это увидел, это было откровение!;)
Ответ 2
@Абрахам Пинзур; Следуя ссылке, приведенной в этой статье, вы найдете этот фрагмент:
static void Main(string[] args)
{
Console.WriteLine("Name is '{0}'", GetName(new {args}));
Console.ReadLine();
}
static string GetName<T>(T item) where T : class
{
var properties = typeof(T).GetProperties();
return properties[0].Name;
}
Что создает "Имя - это" args ". Метод Rinat использует имя свойства, сгенерированное компилятором С#, для создания анонимного типа в выражении new{args}
. Полная статья здесь: http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
- Edit -
Прочитав далее статью Rinat, это также можно сделать, создав дерево выражений и просматривая либо дерево, либо содержащее его IL. В принципе, прочитайте связанную статью!
Ответ 3
Ринат Абдуллин делает что-то вроде этого, анализируя IL из анонимного метода (или выражения лямбда). Его полный код здесь.
Итак, ваш пример будет выглядеть так:
class Program
{
static void Main (string[] args)
{
var variable = "asdf";
var v1 = GetVariableName(() => variable); // returns "variable"
}
static string GetVariableName (Func<object> variable)
{ // Again, credit to Mr. Abdullin ...
var il = variable.Method.GetMethodBody().GetILAsByteArray();
var fieldHandle = BitConverter.ToInt32(il,2);
var field = variable.Target.GetType()
.Module.ResolveField(fieldHandle);
return field.Name;
}
}
Однако это не распространяется напрямую на ваш второй случай (contact.Name
→ "Name"
).
Ответ 4
Это невозможно. То, что отправлено методу в вашем примере, не является самой переменной, а только копией ссылки, которую содержит переменная.
Метод может сканировать все объекты, которые существуют для ссылки среди переменных-членов, но это было бы выполнимо только в том случае, если переменная является членом класса. Локальные переменные невозможно достичь таким образом, поскольку они существуют только в стеке. Кроме того, если одна и та же ссылка существует в более чем одной переменной, метод не сможет определить, какая из них была использована.
В вашем примере свойство Name возвращает нулевую ссылку, конечно, невозможно определить, откуда это взялось.
Если переменная была типом значения, она попала бы внутрь нового объекта в кучу. Поскольку единственной ссылкой на объект в штучной упаковке является тот, который отправляется методу, а объект в штучной упаковке не имеет ссылки на оригинал, невозможно указать, какая переменная была помещена в бокс.