委托与params关键字匹配任何方法?

时间:2009-08-30 10:38:50

标签: c# delegates

我正在努力完成以下事情:

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对象[]作为参数?...

3 个答案:

答案 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]);
};