我正在努力完成以下事情:
public delegate void SomeMethod(params object[] parameters);
那是我的代表。 我有一些方法可以运行这个SomeMethod委托(无论通过什么)并返回执行的时间跨度。
public TimeSpan BenchmarkMethod(SomeMethod someMethod, params object[] parameters)
{
DateTime benchmarkStart = DateTime.Now;
someMethod(parameters);
DateTime benchmarkFinish = DateTime.Now;
return benchmarkFinish - benchmarkStart;
}
我也有一些方法:
public abstract void InsertObjects (Company c);
所以,我宣布:
SomeMethod dlg = new SomeMethod(InsertObjects);
TimeSpan executionTime = BenchmarkMethod(dlg, c);
但它没有运行,说'InsertObjects'没有重载匹配委托'TestFactory.MeasuringFactory.SomeMethod'。有没有办法做到这一点?或者我应该改变我的所有方法来接受params对象[]作为参数?...
答案 0 :(得分:4)
严格来说,方法签名必须与委托指定的签名完全匹配(协变匹配除外)。但是,您可以创建object[]
数组并将其提供给Delegate.DynamicInvoke(object[] args)
。
编辑:
如果您有关于要调用的方法的信息,可以使用MethodBase.GetParameters().Length
来获取参数的数量,这样就可以正确调整无类型参数数组的大小。
但是,对于基准测试,我认为您最好使用实现必要的基准测试操作的抽象基类:
abstract class Benchmark
{
TimeSpan Run()
{
Stopwatch swatch = Stopwatch.StartNew();
// Optionally loop this several times and divide elapsed time by loops:
RunMethod();
swatch.Stop();
return swatch.Elapsed;
}
///<summary>Override this method with the code to be benchmarked.</summary>
protected abstract void RunMethod()
{
}
}
虚拟方法调度具有与委托相当的延迟,并且比动态调用要好得多。
答案 1 :(得分:4)
代表是否与params关键字匹配任何方法?
没有。 他们仍然必须尊重类型差异。
params只是合成糖,因为从那时起,呼叫站点的所有参数都被认为是该方法上同一个数组的一部分。
因此,对于定义为:
的方法
TimeSpan BenchmarkMethod(SomeMethod someMethod, params Company[] parameters)
你可以这样做:
Company company1 = null;
Company company2 = null;
//In BenchmarkMethod, company1 and company2 are considered to be part of
//parameter 'parameters', an array of Company;
BenchmarkMethod(dlg, company1, company2);
但不是:
Company company1 = null;
object company3 = new Company();
BenchmarkMethod(dlg, company1, company3);
因为虽然company3在运行时包含公司,但它的静态类型是对象。
所以现在我们知道params只是在方法上定义一个数组,它允许你在调用站点使用更方便的语法。
现在让我们继续说明您的代码无法正常工作的真正原因:输入差异
您的代理人定义为:
public delegate void SomeMethod(params object[] parameters);
,您将方法定位为:
public abstract void InsertObjects (Company c);
调用委托时:
SomeMethod dlg = new SomeMethod(InsertObjects);
TimeSpan executionTime = BenchmarkMethod(dlg, c);
你很重要的是,你可以调用InsertObjects传递一个包含任何类型对象的数组,而不是类型为Company的对象。
编译器当然不允许这样做。
相反,如果您反转委托的类型和目标方法,例如:
public delegate void SomeMethod(params Company[] parameters);
public TimeSpan BenchmarkMethod(SomeMethod someMethod, params Company[] parameters) {
DateTime benchmarkStart = DateTime.Now;
someMethod(parameters);
DateTime benchmarkFinish = DateTime.Now;
return benchmarkFinish - benchmarkStart;
}
public void InsertObjects(object c) {
Console.WriteLine(c);
}
然后它将编译,因为您将把Customer数组传递给接受任何类型对象的方法。
<强>结论:强> params不影响类型方差规则。
答案 2 :(得分:2)
匹配params
参数是编译器魔术,并且代理人不存在这样的魔法。它将匹配一个在正确位置具有兼容类型数组的方法,但没有别的。
所以是的,您需要更改所有方法,或使用匿名方法作为包装器,如下所示:
SomeMethod dlg = new SomeMethod(delegate(Object[] parameters)
{
InsertObjects((Company)parameters[0]);
};