C# - 是否可以从Action中获取方法的所有者类型?

时间:2010-07-30 11:40:50

标签: c# delegates action

我有一个用一些方法实现接口的类。 我也有一个Action参数的方法,我传递了Interface方法。 是否有可能获得拥有该方法的所有者的类型?

EDIT 这是包装器:

private void Wrapper (params Action[] actions)
{
    var action = actions.FirstOrDefault();
    var type = action.Method.DeclaringType.Name;
}

private void test()
{
   Wrapper(()=> _GC.ChargeCancellation(""));
}

出于演示目的,我不会遍历该集合。

我想要_GC的类型。

2 个答案:

答案 0 :(得分:4)

编辑:我误读了这个例子,并认为它正在使用方法组转换。你当然可以在委托中获取方法:

public void Wrapper(Action action)
{
    MethodInfo method = action.Method;
    Type type = method.DeclaringType; // TestClass
    string name = method.Name; // Hello
}

如果你传递一个带有多个动作的委托实例,我不确定会使用哪种方法......但在这种情况下它应该不是问题。

多哈 - 我误解了这个问题。当你使用lambda表达式时,它将在调用类中构建一个额外的方法 - 而 是包含对_GC的引用的方法。

如果您不想要此行为,则应将Wrapper更改为接受params Expression<Action>[] actions - 然后您可以适当地检查表达式树并找出这种方式的调用。有时它有点繁琐,但它是可行的。查看表达式树的Body,它将代表方法调用。请注意,如果您仍想执行操作,可以在表达式树上调用Compile以获取委托。

答案 1 :(得分:4)

实际上,我应该从一开始就发现这一点,但既然乔恩没有,我也不会感到太糟糕:)

您在问题中必须编写的代码无法编译:

Wrapper(() => TestClass.Hello);

这不是完整的代码。你要么必须:

Wrapper(TestClass.Hello);
        ^
        |
        +-- notice the missing () => here

或:

Wrapper(() => TestClass.Hello());
                             ^
                             |
                             +-- notice the added parenthesis here

现在你已经编辑了你的问题,很明显你有第二种形式。

两者之间存在细微差别。对我们来说很微妙,但对编译器很重要:

Wrapper(TestClass.Hello);
        ^------+------^
               |
               +-- This is a method group

Wrapper(() => TestClass.Hello());
              ^------+--------^
                     |
                     +-- This is a method call

方法组是对方法(或其重载)的引用,方法调用是可执行代码。

编译器的不同之处在于,在第一段代码中,编译器会将方法组包装成一个动作,基本上就像这样编译它:

Wrapper(new Action(TestClass.Hello));

因此,您将该方法传递给Action委托内的Wrapper方法。

但是,第二种形式的处理完全不同。编译器现在生成一个包含代码的新方法,然后将新方法传递给Wrapper方法而不是您拥有的代码。

因此,您的代码实际上如下所示:

public static void Main()
{
    Wrapper(new Action(TempMethod1));
}

private static void TempMethod1()
{
    TestClass.Hello();
}

这就是为什么你看到表单类作为方法的所有者,因为它就是它的原因。

我在评论中询问您是否正在接受代表或表达的原因是我的大脑正以半速运转。它发现了一些奇怪的东西,但不是整个画面。

如果您想将这样的代码传递给方法并使用它,您有两种选择:

  1. 对于委托,使用反射,反编译代码并对其进行分析,找到方法调用并找出它所在的类
  2. 对于表达式,分析表达式的部分(这需要C#3或更高版本)
  3. 由于这两件事都不重要,我不打算在这里发布任何代码,只要说你要问的是一个新问题。在这两个中,如果可以,我建议你采用表达方式。