从Action <t> </t>获取参数

时间:2010-12-05 21:28:13

标签: c# reflection action

如何将参数传递到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。但它们似乎都没有包含我所追求的数据(我认为这是因为我宣布了Action的方式)。感谢

编辑:这不是我想要的类型,它是实际值 - 如注释位代码中所述。

3 个答案:

答案 0 :(得分:9)

要做到这一点,它实际上应该是Expression<Action<T>>。然后是分解表达式的情况。幸运的是,我在protobuf-net here中拥有了所有代码 - 特别是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;
}

答案 1 :(得分:5)

它应该是这样的:

 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,但你应该可以从那里开始

答案 2 :(得分:3)

您的操作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)))