具有动态数量的参数类型

时间:2016-12-27 10:54:30

标签: c# generics

我需要编写一种消耗其他方法的方法作为"动作"用它做某事(例如记录)。

这是我的方法:

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,并且不能使用每个类或类型。

3 个答案:

答案 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