我目前的代码与python装饰器非常相似,它将函数作为参数并返回由另一个函数包装的相同函数(在这种情况下打开和关闭perforce连接)。
public Func<TArg, TReturn> EnableP4<TReturn, TArgs>(Func<TArg, TReturn> function)
{
Func<TArg, TReturn> p4Wrapper = (TArg funcArg) =>
{
try
{
if (con.Status.Equals(ConnectionStatus.Disconnected)) { con.Connect(options); }
return function(funcArg);
}
finally { con.Disconnect(); }
};
return p4Wrapper;
}
目前这只适用于带有一个参数的函数,我想知道它是否可以更通用(也许是否有一种方法可以将数组解压缩到方法中?)。
(有点像这样吗?)
public Func<TArgs, TReturn> EnableP4<TReturn, TArgs>(Func<TArgs, TReturn> function)
{
Func<TArgs, TReturn> p4Wrapper = (TArgs args) =>
{
try
{
if (con.Status.Equals(ConnectionStatus.Disconnected)) { con.Connect(options); }
return function(*args);
}
finally { con.Disconnect(); }
};
return p4Wrapper;
}
其中TArgs是TArg []。
答案 0 :(得分:6)
你可以使用Func<T>
(不是Func<TArg,TResult>
),并允许编译器通过lambda表达式中的闭包来处理多个参数。
如果您将方法更改为:
public Func<T> EnableP4<T>(Func<T> function)
您可以随时通过以下方式致电:
var newFunc = EnableP4(() => SomeFunc(arg1, arg2, arg3));
这很好,因为它允许任意数量的参数而不会有多次重载。
答案 1 :(得分:1)
不,您可以使用强类型结果在C#中完成此操作。它主要是由于返回类型 - 您可以相对容易地构造调用具有任意数量参数的函数(即Emit或反射),但是要具有强类型结果,您将必须具有多个函数。
通常的方法是为0-n(通常0-3足够)的每个参数提供多个函数。
public Func<TReturn> EnableP4<TReturn>(Func<T1, TReturn> function)...
public Func<T1, TReturn> EnableP4<TReturn, T1>(Func<T1, TReturn> function)....
public Func<T1, T2, TReturn>
EnableP4<TReturn, T1, T2>(Func<T1, T2, TReturn> function)...
注意:
dynamic
来查看是否接近您想要的内容答案 2 :(得分:0)
您不需要传递所有参数;相反,你可以传递一个已经提供参数的lambda。
通过一个例子可以很容易地解释这一点。鉴于此:
public Func<T> Wrapper<T>(Func<T> function)
{
Func<T> wrapper = () =>
{
try
{
Console.WriteLine("Prequel");
return function();
}
finally
{
Console.WriteLine("Sequel");
}
};
return wrapper;
}
你可以这样做:
void run()
{
// Supply arguments to test() here:
var wrapped = Wrapper(() => test(1, 2));
Console.WriteLine(wrapped());
}
private int test(int a, int b)
{
Console.WriteLine("test()");
return a + b;
}
答案 3 :(得分:0)
可变数量的类型参数是unsupported in C#,所以我认为用你现有的东西做你想做的事是不可能的。 .Net框架本身有that many func/action delegate declarations是有原因的。在同一命名空间中,使用元组也可以看到这一点。
我认为你可以使用参数对象解决它,它基本上是一个封装所有参数的类。如果您随后为这些模型创建基类或接口,则可以限制装饰器方法:
public Func<TArgs, TReturn> EnableP4<TReturn, TArgs>(Func<TArgs, TReturn> function)
where TArgs : IArgs
这与框架内事件中使用的概念非常相似,其中传递了EventArgs参数对象。这里的想法是一样的,你必须继承基础模型/接口,并用你想要的参数创建特定的模型。
这当然不是最优的,因为它需要进行大量修改,并且对于简单的方法调用是非标准的,但我认为它应该可以正常工作。
你有没有考虑过方法拦截?我知道Unity supports it例如。