C# 作为参数的Pass方法
我正在使用C#中的一个库,其中一个方法要求我将目标方法的字符串名称作为参数传递 出于明显的原因,我希望避免使用硬编码字符串,因此我将编写一个中间util方法,该方法接受一个方法,获取名称(可能是通过反射),并将其提供给库方法 我希望中间方法看起来像这样:C# 作为参数的Pass方法,c#,reflection,methods,C#,Reflection,Methods,我正在使用C#中的一个库,其中一个方法要求我将目标方法的字符串名称作为参数传递 出于明显的原因,我希望避免使用硬编码字符串,因此我将编写一个中间util方法,该方法接受一个方法,获取名称(可能是通过反射),并将其提供给库方法 我希望中间方法看起来像这样: public void CallOtherMethod(???? inputMethod) { string methodName = inputMethod.Name; // This gives me the method with
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,就像这个答案一样,还是直接传递命名方法?后者将导致此处提供方法的名称,前者不应。如果是这样,那就错了。