2009-09-06 6 views
2

Я ищу способ получить имя переменной, поэтому мне не нужно использовать жестко объявленные объявления при необходимости (имена свойств и т. Д.):Получить переменное (не жестко запрограммированное) имя?

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

'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, либо в C#.

+1

То, что вы пытаетесь сделать, невозможно, если я правильно понимаю ваш вопрос. Не могли бы вы использовать прецедент?Что вы на самом деле пытаетесь достичь здесь? – Dirk

+0

Дубликат http://stackoverflow.com/questions/72121/finding-the-variable-name-passed-to-a-function-in-c – adrianbanks

ответ

5

О есть простое решение, использовать деревья выражений здесь пример, просто адаптироваться к вашим потребностям в C#

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" 

В первый раз я видел это, это было откровение! ;)

+0

Это отличное решение, возможно, не так быстро, как синтаксический анализ IL, но, возможно, более элегантный (и менее подверженный ошибкам). –

+0

Ты мужчина! Я бы не поверил! – Shimmy

+1

+1 Кроме того, вы можете использовать анонимный объект для передачи в локальной переменной, например, «Dim variable» в OP. Например, var propertyName = GetPropertyName (() => new {variable} .variable); – StarTrekRedneck

3

Rinat Abdullin doing something like this путем разбора IL от анонимного метода (или выражения лямбда). Его full code is here.

Итак, ваш пример будет выглядеть так:

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").

+0

Существует более простое решение с деревьями выражений, и кажется, что вы «Я сделал, см. мой ответ –

2

Это невозможно. То, что отправлено методу в вашем примере, - это не сама переменная, а только копия ссылки, которую содержит переменная.

Метод может сканировать все объекты, которые существуют для ссылки среди переменных-членов, но это было бы выполнимо только в том случае, если переменная является членом класса. Локальные переменные невозможно достичь таким образом, поскольку они существуют только в стеке. Кроме того, если одна и та же ссылка существует в более чем одной переменной, метод не сможет определить, какая из них была использована.

В вашем примере свойство Name возвращает нулевую ссылку, конечно, невозможно определить, откуда это взялось.

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

+2

Нет, это возможно, см. мой ответ, выражение деревьев powaaaa! –

+0

@Slashene: Да, если вы полностью измените способ вызова метода. Что-то вроде OP не возможно. – Guffa

5

@Abraham Pinzur; После дополнительной ссылки в статье вы связаны обеспечивает этот фрагмент кода:

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; 
} 

Что делает произвести «имя„арг“». Метод Rinat использует имя свойства, сгенерированное компилятором C#, для создания анонимного типа в выражении new{args}. Полный текст статьи здесь: http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html

--Edit--

Прочитав далее в статье Ринат, это также может быть сделано путем получения дерева выражений и просмотра либо дерево, либо IL она содержит. В принципе, прочитайте связанную статью!

+0

Я никогда не думал использовать анонимные типы для этого, красивые подсказки! –

+0

+1 Это круто! –