Получить переменное (не жестко запрограммированное) имя?

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

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

'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 возвращает нулевую ссылку, конечно, невозможно определить, откуда это взялось.

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