C# 作为参数的Pass方法

C# 作为参数的Pass方法,c#,reflection,methods,C#,Reflection,Methods,我正在使用C#中的一个库,其中一个方法要求我将目标方法的字符串名称作为参数传递 出于明显的原因,我希望避免使用硬编码字符串,因此我将编写一个中间util方法,该方法接受一个方法,获取名称(可能是通过反射),并将其提供给库方法 我希望中间方法看起来像这样: public void CallOtherMethod(???? inputMethod) { string methodName = inputMethod.Name; // This gives me the method with

我正在使用C#中的一个库,其中一个方法要求我将目标方法的字符串名称作为参数传递

出于明显的原因,我希望避免使用硬编码字符串,因此我将编写一个中间util方法,该方法接受一个方法,获取名称(可能是通过反射),并将其提供给库方法

我希望中间方法看起来像这样:

public void CallOtherMethod(???? inputMethod)
{
    string methodName = inputMethod.Name; // This gives me the method without the namespace, right?
    this.CallFinalMethod(methodName);
}
this.CallOtherMethod(this.SomeOtherMethod);
public void CallOtherMethod(Action method)
{
    string methodName = method.Method.Name;
    method.Invoke();
}

 public void AnotherMethod(string foo, string bar)
{
    // Do Something
}
bool success=TryGetName(()=>someObject.SomeMethod(), out name);
这样称呼:

public void CallOtherMethod(???? inputMethod)
{
    string methodName = inputMethod.Name; // This gives me the method without the namespace, right?
    this.CallFinalMethod(methodName);
}
this.CallOtherMethod(this.SomeOtherMethod);
public void CallOtherMethod(Action method)
{
    string methodName = method.Method.Name;
    method.Invoke();
}

 public void AnotherMethod(string foo, string bar)
{
    // Do Something
}
bool success=TryGetName(()=>someObject.SomeMethod(), out name);
但是,我在确定执行此操作所需的类型时遇到了一些困难

如何正确定义我的方法


作为补充说明,我很乐意将此作为库的扩展方法编写,但这与库的行为方式不太相符。

尝试使用
操作
函数
,如下所示:

public void CallOtherMethod(???? inputMethod)
{
    string methodName = inputMethod.Name; // This gives me the method without the namespace, right?
    this.CallFinalMethod(methodName);
}
this.CallOtherMethod(this.SomeOtherMethod);
public void CallOtherMethod(Action method)
{
    string methodName = method.Method.Name;
    method.Invoke();
}

 public void AnotherMethod(string foo, string bar)
{
    // Do Something
}
bool success=TryGetName(()=>someObject.SomeMethod(), out name);
电话:


您需要
委托

public void OtherMethod(Action method)
{
   MessageBox.Show("I am raised first.");
   string methodname = method.Method.Name;
   method.Invoke();
}

public void SomeMethod()
{
    some code ...
}
如果使用命名方法调用OtherMethod

OtherMethod(SomeMethod);
methodName设置为“SomeMethod”,
但是如果你使用匿名方法来调用它

OtherMethod(() => MessageBox.Show("The main thing ..."));

然后您将得到一个讨厌的编译器生成的名称,如
b_u0

如果您的库约束方法具有特定的签名(例如,0参数,返回void),那么您可以使用具有适当签名的委托

例如,
操作
表示一个具有0个参数且返回void的方法

public void CallOtherMethodMethodGroup(Action action)
{
    MethodInfo method = action.Method;

    //check that 'action' is not a compiler generated lambda
    if (!method.IsDefined(typeof (CompilerGeneratedAttribute)))
    {
        Console.WriteLine(method.Name);
    }
    else
        throw new InvalidOperationException("Use 'CallOtherMethodExpr' instead.");
}
并使用一个:

如果您的库接受具有任何类型签名的方法,则使用必须传入lambda而不是方法组:

CallOtherMethodExpr(() => AnotherMethod("dummy", "arg"));
但是,当使用lambda时,您必须更改方法以接受
表达式
,而不是
操作
。表达式可以解释,委托不能

public void CallOtherMethodExpr(Expression<Action> expr)
{
    string methodName;

    if (expr.Body.NodeType == ExpressionType.Call)
    {
        var call = expr.Body as MethodCallExpression;
        methodName = call.Method.Name;
    }
    else
        throw new InvalidOperationException("Expression must contain a method call");

    Console.WriteLine(methodName);
}
public void CallOtherMethodExpr(表达式expr)
{
字符串方法名;
if(expr.Body.NodeType==ExpressionType.Call)
{
var call=expr.Body作为MethodCallExpression;
methodName=call.Method.Name;
}
其他的
抛出新的InvalidOperationException(“表达式必须包含方法调用”);
Console.WriteLine(方法名);
}

据我所知,问题不在于如何通过委托调用方法,而在于如何在不使用魔术字符串的情况下获取方法的名称

使用反射并不会使神奇的字符串消失。您可以获得具有特定签名的类型的所有方法,但仍然需要知道目标方法的名称。简单的重命名重构仍然会破坏代码

这种情况下的典型解决方案是传递一个指向所需成员的表达式。这在MVVM框架中广泛用于传递任何修改参数的名称

以下方法将检查提供的表达式是否为实际的方法调用,并提取方法的名称:

    public static bool TryGetName(Expression<Action> expr, out string memberName)
    {
        memberName = null;
        var body = expr.Body as MethodCallExpression;
        if (body == null)
            return false;
        memberName = body.Method.Name;
        return true;
    }
所有Action和Func对象都继承自Action,这意味着
SomeMethod
实际上可能是一个函数。如果方法包含参数,则调用将需要一些伪值:

bool success=TryGetName(()=>someObject.SomeMethod(null,"dummy",0), out name);

你真的需要这个名字还是调用这个方法就足够了?您想要实现什么?这个库是否有任何特定的签名?例如,所有方法是否都必须采用0个参数并返回void?或者图书馆能调用你给它的任何方法吗?这能回答你的问题吗@dcastro获取方法名称很容易,请查看更新的答案。
methodName
将设置为编译器生成的名称(即
b_u0
),而不是
AnotherMethod
@dcastro,如果我使用匿名方法?是的,如果我使用命名方法?不,这不是你的代码显示的。你的
methodName
不可能被设置为
Show
。你不认为这与答案相关吗?
methodName
将被设置为编译器生成的名称(即
b_u0
),而不是
AnotherMethod
。非常感谢!我完全忘记了方法有返回值,所以我需要使用Func而不是Action。我不知道你可以这样使用代理。在Windows上不工作。这个答案似乎取决于一个实现上的怪癖,这种怪癖可以在不改变的情况下改变notice@Vesuvian您真的想编写只在特定编译器上工作的代码吗?您应该:a)只传入方法组,或者b)使用表达式计算lambda。从lambda中检索方法名而不使用表达式是有风险的。@Vesuvian您是使用lambda,就像这个答案一样,还是直接传递命名方法?后者将导致此处提供方法的名称,前者不应。如果是这样,那就错了。