【问题标题】:Using a strongly typed method as an argument without specifying parameters使用强类型方法作为参数而不指定参数
【发布时间】:2011-11-08 00:17:10
【问题描述】:

是否可以在不提供参数和/或括号的情况下将方法的强类型名称作为 lambda 表达式传递?

例如,如果我有以下方法:

public class CalleeClass
{
    public void MethodA(obj param1, obj param2)
    {
        ...
    }
}

我想通过以下方式在别处调用此方法:

return new MyClass<CalleeClass>(c => c.MethodA); //Note: no ()'s or arguments

MyClass 将负责使用方法名称作为目标的 MVC 路由。这里的目标是我们希望能够通过控制器方法使用强类型视图,并且我不想提供不被使用的“哑”参数。

目前,我正在使用类似于以下的代码来使用方法名称,但这种风格仍然需要传入假参数和/或括号。

public void MyClass<T>(Expression<Action<T>> action)
{
    var methodName = (action.Body as MethodCallExpression).Method.Name;
}

编辑:很抱歉造成混淆,但我最初试图通过仅包含我认为您需要的内容来简化问题,并在这样做时遗漏了一些关键信息。这里的最终目标是让 MyClass 接收到泛型类型 + lambda 表达式,并且 lambda 表达式可以传入强类型方法名,而无需实例化对象。 -MB

【问题讨论】:

  • 可以不设置可选参数吗?另外: MethodCallExpression 除非我很确定它有括号,否则它不会起作用。
  • 参数不傻;它们被编译器使用...
  • 没有冒犯参数,但我们只需要路由的方法名称,给人的印象是我们正在实例化一个对象似乎很奇怪。我不相信这是可能的,这就是我来这里的原因。 :)
  • 为什么不使用 MethodInfo?类似于: var method = typeof(AClass).GetMethods().Where((m) => m.Name.Equals(@"MethodA")).FirstOrDefault();然后在MyClass中使用method作为你需要的参数。

标签: c# linq asp.net-mvc-3 delegates


【解决方案1】:

你实际上可以不带参数传递方法:

class PassActionTest
{
    public void Test( )
    {
        var c = new C();
        var myClass =  new MyClass(c.MethodA); 
    }
}

class MyClass
{
    public MyClass(Action<object,object> action)
    {
        string methodName = action.Method.Name;
    }
}

class C
{
    public void MethodA(object param1, object param2)
    {
    }
}

EDIT:根据 Matt Beckman 的 EDIT,不应实例化包含 MethodA 的类。我的新解决方案是:

class PassActionTest
{
    public void Test()
    {
        var myClass = new MyClass(c => c.MethodA);
    }
}

class MyClass
{
    public MyClass(Expression<Func<C, Action<object, object>>> expr)
    {
        UnaryExpression unaryExpr = (UnaryExpression)expr.Body;
        MethodCallExpression methodCallExpr = (MethodCallExpression)unaryExpr.Operand;
        ConstantExpression constantExpr = (ConstantExpression)methodCallExpr.Arguments[2];
        MethodInfo methodInfo = (MethodInfo)constantExpr.Value;
        string methodName = methodInfo.Name;
    }

}

class C
{
    public void MethodA(object param1, object param2)
    {
    }
}

解析表达式有点复杂,但我测试过,它可以工作。

【讨论】:

  • 为了简化这里的问题,我想我忘了补充这一行应该是:return new MyClass(c => c.MethodA) ,因为我不想实例化具有 MethodA 方法的类。请参阅上面的更改。
  • 查看this commentthis answer 以了解v4.5 运行时的用法。
  • 从 C#6.0 开始,您将能够使用 nameof() 运算符。 string s = nameof(c.MethodA)
【解决方案2】:

如果您只需要方法名称,我建议使用Delegate (http://msdn.microsoft.com/en-us/library/system.delegate.aspx):

public MyClass(Delegate action)
{
    var methodName = action.Method.Name;
}

这可行,但我认为您需要在传入时指定委托类型:

{
    ...
    return new MyClass((Action<object,object>)c.MethodA);
}

这将使所有内容保持强类型,以便重构也可以工作。

【讨论】:

    【解决方案3】:

    您可以声明一个与 MethodA() 方法的签名匹配的委托,并将该委托用作 MyClass 类的构造函数的参数

    public delegate void MethodADelegate(object param1, object param2);
    
    public MyClass(MethodADelegate methodParam)
    {
        //use the methodParam parameter
    }
    

    或者,您可以按照@Olivier 的建议使用 .Net 中的 Action 委托

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多