Получить параметры из действия <T> - PullRequest
6 голосов
/ 06 декабря 2010

Как получить параметры, переданные в Action<T>? Пример кода должен подчеркнуть то, что я пытаюсь достичь. Извините, что это немного долго.

class Program
{
    static void Main(string[] args)
    {
        Foo foo = new Foo();
        foo.GetParams(x => x.Bar(7, "hello"));
    }
}

class Foo
{
    public void Bar(int val, string thing) { }
}

static class Ex
{
    public static object[] GetParams<T>(this T obj, Action<T> action)
    {
        // Return new object[]{7, "hello"}
    }
}

Единственные опции, которые выглядят неопределенно полезными, - это GetInvocationList (), Method и Target. Но ни одна из них, похоже, не содержит данных, которые мне нужны (я думаю, это из-за того, как я объявил Действие). Спасибо

РЕДАКТИРОВАТЬ: это не типы, которые я хочу, а фактические значения - как отмечено в комментируемом бите кода.

Ответы [ 3 ]

9 голосов
/ 06 декабря 2010

Для этого на самом деле должно быть Expression<Action<T>>. Тогда это случай разложения выражения. К счастью, у меня есть весь код для этого в protobuf-net, здесь - в частности ResolveMethod, который возвращает значения в массиве out (после обхода любых захваченных переменных и т. Д.).

После публикации ResolveMethod (и удаления всего выше ResolveMethod) код выглядит так:

public static object[] GetParams<T>(this T obj, Expression<Action<T>> action)
{
    Action ignoreThis;
    object[] args;
    ProtoClientExtensions.ResolveMethod<T>(action, out ignoreThis, out args);
    return args;
}
5 голосов
/ 06 декабря 2010

Это должно быть примерно так:

 public static object[] GetParams<T>(this T obj, Expression<Action<T>> action)
    {
        return ((MethodCallExpression) action.Body).Arguments.Cast<ConstantExpression>().Select(e => e.Value).ToArray();
    }

Вы должны выполнить некоторую проверку, чтобы убедиться, что в действие не может быть отправлено ничего недопустимого, поскольку не все будет приведено к выражению MethodCallExpression, но вы должны быть в состоянии выполнить оттуда

3 голосов
/ 06 декабря 2010

Ваше действие x => x.Bar(7, "hello") может быть переписано как

void action(T x)
{
    return x.Bar(7, "hello");
}

Теперь ясно, что 7 и "hello" не являются параметрами действия, только x - это.

Чтобы получить доступ к 7 и "hello", вам нужен доступ к выражению, как предлагает @Marc. Однако неясно, как ваш код должен обрабатывать более сложные выражения, такие как x => 1 + x.Bar(7, x.Baz("hello", x.Quux(Application.Current))).

...