Получить свойство из локальной переменной по строке

Внутри метода я делаю несколько вызовов веб-службы для получения данных, например:

public void SomeMethod()
{
    var user = userWS.GetUsers();
    var documents = documentWS.GetDocuments();
}

У меня также есть файл XML, в котором пользователь может указать, какое свойство сопоставлять. XML-код выглядит следующим образом:

<root>
  <item id="username" mapper="user.username.value" />
  <item id="document1" mapper="documents.document1.value" />
</root>

Итак, что я в основном хочу сделать, это выполнить строку, которая находится внутри атрибута mapper. Так что у меня есть что-то вроде этого:

public void SomeMethod()
{
    var user = userWS.GetUsers();
    var documents = documentWS.GetDocuments();

    // returns: "user.username.value"
    string usernameProperty = GetMapperValueById ( "username" );

    var value = Invoke(usernameProperty);
}

Так что это должно действовать так, как если бы я вызывал var value = user.username.value; вручную в своем коде.

Но как я могу вызвать это действие из string?


person Vivendi    schedule 10.12.2013    source источник
comment
Я предоставил метод GetPropertyValue, который будет соответствовать вашим потребностям, в этот ответ   -  person Konrad Kokosa    schedule 10.12.2013
comment
Я не уверен, что это тот ответ, который я ищу. Речь идет о локальной переменной внутри метода, который мне нужно выполнить. Я думаю, мне нужно больше функции Eval для этого. Но, к сожалению, это не так просто, как я думал   -  person Vivendi    schedule 10.12.2013
comment
этого будет достаточно, я собираюсь дать ответ с надлежащим примером.   -  person Konrad Kokosa    schedule 10.12.2013
comment
@Vivendi единственный способ выполнить динамический код — через CodeDOM. Однако вы можете сделать это с помощью рефлексии — просто это будет не так просто, как хотелось бы.   -  person James    schedule 10.12.2013


Ответы (1)


Как правило, вы не можете получить значения локальных переменных во время выполнения (см. -local-variables">этот вопрос для справки), но на основе моего собственного ответ на другой вопрос, вы можете использовать метод GetPropertyValue, чтобы обойти эту проблему, создав локальный объект с нужными свойствами:

public void SomeMethod()
{
    var container = new 
    {
        user = userWS.GetUsers(),
        documents = documentWS.GetDocuments()
    }

    // returns: "user.username.value"
    string usernameProperty = GetMapperValueById ( "username" );

    var value = GetPropertyValue(container, usernameProperty);
}

static object GetPropertyValue(object obj, string propertyPath)
{
    System.Reflection.PropertyInfo result = null;
    string[] pathSteps = propertyPath.Split('.');
    object currentObj = obj;
    for (int i = 0; i < pathSteps.Length; ++i)
    {
        Type currentType = currentObj.GetType();
        string currentPathStep = pathSteps[i];
        var currentPathStepMatches = Regex.Match(currentPathStep, @"(\w+)(?:\[(\d+)\])?");
        result = currentType.GetProperty(currentPathStepMatches.Groups[1].Value);
        if (result.PropertyType.IsArray)
        {
            int index = int.Parse(currentPathStepMatches.Groups[2].Value);
            currentObj = (result.GetValue(currentObj) as Array).GetValue(index);
        }
        else
        {
            currentObj = result.GetValue(currentObj);
        }

    }
    return currentObj;
}
person Konrad Kokosa    schedule 10.12.2013
comment
+1 идея container приятная. Это можно улучшить, сделав GetPropertyValue универсальным. - person James; 10.12.2013
comment
Большое спасибо, кажется, это помогает! Я изменил оба result.GetValue(currentObj) на result.GetValue(currentObj, null) в своем коде, так как он ожидает два параметра. - person Vivendi; 10.12.2013