我想知道是否有办法定义具有可变数量参数的通用函数。例如,我已经定义了泛型函数:
public T MeasureThis<T>(Func<T> funcToMeasure)
{
var watch = new Stopwatch();
watch.Start();
T returnVal = funcToMeasure();
watch.Stop();
Console.WriteLine("Time elapsed: {0}", watch.Elapsed);
return returnVal;
}
还有:
public T MeasureThis<T>(Func<int,int,T> funcToMeasure, int p1, int p2)
{
var watch = new Stopwatch();
watch.Start();
T returnVal = funcToMeasure(p1, p2);
watch.Stop();
Console.WriteLine("Time ellapsed: {0}", watch.Elapsed);
return returnVal;
}
我想测量直到最后需要执行的时间函数。问题是要测量的函数可以没有,一个,两个,三个......参数。如果我想测量包含10个参数的函数,我应该定义相同函数的十倍吗?
谢谢!
答案 0 :(得分:1)
一个简单的技巧是使用最简单的Func<T>
返回一个类型,而不是将其他类型作为类型参数传递给泛型,你可以使用一个闭包从周围的上下文中捕获它们。 / p>
例如:
int SomeFunctionWith3Args(int arg1, int arg2, int arg3) { ... }
int[] arg = new int[] { 1, 2, 3 };
var x = MeasureThis<int>(() => SomeFunctionWith3Args(arg[0], arg[1], arg[2]));
如果您不熟悉这种闭包是如何工作的,它基本上会创建一个新类型,它将您捕获的参数作为字段存储,并将lambda实现为类的方法 - 然后替换调用站点使用类的实例化和对方法的调用。例如,以上(概念上)等同于:
int[] arg = new int[] { 1, 2, 3 };
var closure = new TheClosure();
closure._captured = arg;
var x = MeasureThis<int>(closure.TheLambda());
,其中
class TheClosure {
public int[] _captured;
public int TheLambda() {
return SomeFunctionWith3Args(_captured[0], _captured[1], _captured[2]);
}
}
答案 1 :(得分:1)
使用另一个泛型类型X来表示具有许多属性的类。
public T MeasureThis<T>(Func<X,T> funcToMeasure, X x) where X : class
{
var watch = new Stopwatch();
watch.Start();
T returnVal = funcToMeasure(x);
watch.Stop();
Console.WriteLine("Time ellapsed: {0}", watch.Elapsed);
return returnVal;
}
答案 2 :(得分:1)
如果您正在使用库存CLR代理(例如Func<T,TResult>
),则您的方法需要匹配代理签名。您可以使用可选参数创建方法:
public int Foo( int x , int y = int.MinValue ) { ... }
并将其分配给适当的代理人没有问题:
Func<int,int,int> delegateX = Foo ;
(但请注意,通过委托调用时,您将无法省略第二个参数)。但你不能这样做:
Func<int,int> delegateY = Foo ;
然而,没有什么可以阻止你创建自己的代表。您不需要使用CLR提供的标准代理。
随着更多采用可选参数的方法......你可以这样做:
public TResult Foo<T1,T2,TResult>( T1 p0 , params T2[] p1 ) { ... }
允许您使用任意数量的值调用第二个参数的方法。
您可以使用重载:
public TResult Foo<T1,T2,TResult( T1 p0 , T2 p1 , T2 p2 , T2 p3 ) { ... }
public TResult Foo<T1,T2,TResult( T1 p0 , T2 p1 , T2 p2 ) { ... }
public TResult Foo<T1,T2,TResult( T1 p0 , T2 p1 ) { ... }
您可能希望结合上述两种方法,因为使用params T[]
会产生一定的开销。这种方法允许编译器选择最合适的重载,从而避免构造params
数组的费用:
public TResult Foo<T1,T2,TResult>( T1 p0 , T2 p1 ) { ... }
public TResult Foo<T1,T2,TResult>( T1 p0 , T2 p1 , T2 p2 ) { ... }
public TResult Foo<T1,T2,TResult>( T1 p0 , T2 p1 , T2 p2 , T2 p3 ) { ... }
public TResult Foo<T1,T2,TResult>( T1 p0 , params T2[] p1 ) { ... }
您可以使用具有默认值的方法,例如:
public TResult Foo<T1,T2,TResult>( T1 p0 , T2 p1 = default(T2) , T2 p2 = default(T2) ) { ... }
应该注意,当你有涉及可选参数的方法重载时会有陷阱:
有多种方法可以做到。