как перечислить переданные параметры метода - PullRequest
11 голосов
/ 14 января 2010

Можно перечислить типы / информацию о параметрах вызываемого метода следующим образом:

private void SomeMethod(int thisValue, string thatValue)
{
  StackTrace stackTrace = new StackTrace();
  foreach (ParameterInfo pInfo in stackTrace.GetFrame(0).GetMethod().GetParameters())
  {
    string name = pInfo.Name;
    string type = pInfo.GetType().ToString();
  }
}

Но есть ли способ получить фактический объект каждого параметра?

EDIT : Моя цель - перечислить все параметры и получить их значения. Используя выражения LinQ, можно получить значение параметра следующим образом:

private void SomeMethod(int thisValue, string thatValue)
{
  object valueOfThis = GetParameterValue(() => thisValue);
  object valueOfThat = GetParameterValue(() => thatValue);
}
private object GetParameterValue<T>(Expression<Func<T>> expr)
{
  var body = ((MemberExpression)expr.Body);
  return ((FieldInfo)body.Member).GetValue(((ConstantExpression)body.Expression).Value);
}

Но я бы хотел сделать что-то вроде:

foreach (fooObject o in thisMethod.GetParameterObjects())
{
  object someValue = GetParameterValue(() => fooObject);
}

И, следовательно, есть универсальный метод для сбора всех параметров и их значений.

Ответы [ 3 ]

9 голосов
/ 14 января 2010

UPDATE:

Похоже, я "слишком усложнил" первоначальный ответ, пытаясь объяснить все. Вот краткая версия ответа.

private static void SomeMethod(int thisValue, string thatValue)  
{ 
    IEnumerable<object> parameters = GetParameters(() => SomeMethod(thisValue, thatValue)); 
    foreach (var p in parameters) 
        Console.WriteLine(p); 
}
private static IEnumerable<object> GetParameters(Expression<Action> expr)
{
    var body = (MethodCallExpression)expr.Body;
    foreach (MemberExpression a in body.Arguments)
    {
        var test = ((FieldInfo)a.Member).GetValue(((ConstantExpression)a.Expression).Value);
        yield return test;
    }
}

А вот длинная версия с некоторыми пояснениями.

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

    static void Main(string[] args)
    {

        // First approach.
        IEnumerable<object> parameters = GetParametersFromConstants(() => SomeMethod(0, "zero"));
        foreach (var p in parameters)
            Console.WriteLine(p);

        // Second approach.
        int thisValue = 0;
        string thatValue = "zero";
        IEnumerable<object> parameters2 = GetParametersFromVariables(() => SomeMethod(thisValue, thatValue));
        foreach (var p in parameters2)
            Console.WriteLine(p);

        Console.ReadLine();
    }

    private static void SomeMethod(int thisValue, string thatValue) 
    {
        Console.WriteLine(thisValue + " " + thatValue);
    }      

    private static IEnumerable<object> GetParametersFromVariables(Expression<Action> expr)
    {
        var body = (MethodCallExpression)expr.Body;
        foreach (MemberExpression a in body.Arguments)
        {               
            var test = ((FieldInfo)a.Member).GetValue(((ConstantExpression)a.Expression).Value);
            yield return test;
        }
    }

    private static IEnumerable<object> GetParametersFromConstants(Expression<Action> expr)
    {
        var body = (MethodCallExpression)expr.Body;
        foreach (ConstantExpression a in body.Arguments)
        {
            var test = a.Value;
            yield return test;
        }
    }

}

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

1 голос
/ 14 января 2010

Вы можете использовать MethodInfo.GetCurrentMethod().GetParameters(), чтобы получить список параметров метода. Но невозможно получить их значения по рефлексии.

1 голос
/ 14 января 2010

Хорошо, вот сделка.

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

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

Ergo, есть только один способ сделать это. API профилирования.

Я в конечном итоге здесь . В рамках функций профилирования API. Могу поспорить, что есть способ сделать это, что позволяет вам копаться в значениях параметров, вызывая неуправляемый класс из управляемого кода.

Теперь я бы не стал этого делать, потому что уже есть отличные инструменты для профилирования, JetBrains dotTrace, чтобы назвать его одним, а с IntelliTrace в VS2010 все эти головные боли просто исчезнут ... IntelliTrace позволит вам выполнять отладку во время путешествий.

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

// compile with unsafe
unsafe
{
    var p = stackalloc int[1];
    var baseAddr = p - sizeof(int);
}

Теперь вы не можете писать на baseAddr, но вам должно быть разрешено читать его. Сложность состоит в том, чтобы разобраться со стековыми кадрами, и это имеет отношение к соглашению о вызовах, и это вы должны знать наверняка. Вот разброс этого материала, и это быстрый звонок.

С этой информацией и объектами ParameterInfo вы сможете пройтись по аргументам.

Поскольку вы будете работать с необработанными указателями, вам нужно превратить их в управляемые объекты, и для этого есть класс .

Ну вот, иди с ума!

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...