我需要编写一种消耗其他方法的方法作为"动作"用它做某事(例如记录)。
这是我的方法:
public static void Call(Func<T, TResult> action){
Log.Debug(action.Method.Name + " method called");
}
现在我想坚持使用所有可能的方法,比如
private void Method1 (string param1, int param2) { ...}
private ServiceResult Method2 (UserInfo param1, string param2, bool param3, double param4) { ... }
我想把它称为
Call(Method1); // output: "Method1 method called"
Call(Method2); // output: "Method2 method called"
我的问题是,我需要为&#34; Func&lt;&gt;&#34;声明修复参数类型。我的Call-Method的参数。我怎么能以动态/通用的方式做到这一点?
编辑:我使用的是.NET Compact Framework,因此我只提供.NET 3.5 CF,并且不能使用每个类或类型。答案 0 :(得分:3)
如果您只想访问代理的元数据,请使用Delegate
类:
public static void Call(Delegate action){
Log.Debug(action.Method.Name + " method called");
}
如果你想调用代表,事情会变得更复杂:
Acton
有9个版本,Func
有9个版本:每个版本从0到8个参数。如果您希望直接支持这些代理的所有变体,则需要18个Call
方法的重载。
这似乎过多,实际上是,特别是因为您还需要在方法中为委托中的每个参数添加一个参数。我建议使用两个重载并使用lambda表达式:
public static void Call<T>(Func<T> action)
{
return action();
}
public static void Call(Action action)
{
action();
}
private void ExampleWithParams(int param1)
{
//...
}
private int ExampleWithParamsAndReturn(int param1)
{
//...
return param1;
}
像这样打电话给他们:
Call(() => ExampleWithParams(0));
int value = Call(() => ExampleWithParamsAndReturn(0));
答案 1 :(得分:2)
由于Func<T,TResult>
所需的一切都是Method
,您可以从中获取其名称,因此可以使用Delegate
类,所有代表(包括Func<...>
)都来自继承:
public static void Call(Delegate action){
Log.Debug(action.Method.Name + " method called");
}
答案 2 :(得分:1)
如果您不介意使用lambda表达式,那么这些将允许您检查被调用的方法及其参数。参数甚至可以是方法调用本身,我将展示。
以下是一个可以在控制台应用中测试的工作示例:
private static void TestLogAnyMethod()
{
Console.WriteLine("\r\n>> First batch >>");
var x = M1(0, 1.1);
var y = M2("a", true);
var z = M2(GetA(4, 5.0 / 7.0), GetTrue());
Console.WriteLine("\r\n>> Second batch >>");
var x2 = Log(() => M1(0, 1.1));
var y2 = Log(() => M2("a", true));
var z2 = Log(() => M2(GetA(4, 5.0 / 7.0), GetTrue()));
Console.WriteLine("\r\n>> Results >>");
Console.WriteLine(x + " == " + x2);
Console.WriteLine(y + " == " + y2);
Console.WriteLine(z + " == " + z2);
}
private static string GetA(int p, double q)
{
Console.WriteLine("-- Executing GetA");
return "a";
}
private static bool GetTrue()
{
Console.WriteLine("-- Executing GetTrue");
return true;
}
private static string M1(int v1, double v2)
{
return "123abc";
}
private static bool M2(string w1, bool w2)
{
return true;
}
private static T Log<T>(Expression<Func<T>> expr)
{
var funcBody = (MethodCallExpression)expr.Body;
var funcArgs = funcBody.Arguments;
Console.WriteLine("Method call: " + funcBody.Method.Name + "(" + string.Join(", ", funcArgs.Select(p => p.ToString())) + ")");
Func<T> f = expr.Compile();
return f();
}
我使用非平凡的测试用例来说服自己GetA()和GetTrue()只在Log(...)中被调用一次,更具体地说,仅在f();
执行时被调用。
输出:
>> First batch >>
-- Executing GetA
-- Executing GetTrue
>> Second batch >>
Method call: M1(0, 1.1)
Method call: M2("a", True)
Method call: M2(GetA(4, 0.714285714285714), GetTrue())
-- Executing GetA
-- Executing GetTrue
>> Results >>
123abc == 123abc
True == True
True == True