代码之家  ›  专栏  ›  技术社区  ›  0100110010101

带有params关键字的委托是否与任何方法匹配?

  •  3
  • 0100110010101  · 技术社区  · 16 年前

    我正在努力完成以下工作:

    public delegate void SomeMethod(params object[] parameters);
    

    那是我的代表。 我有一些方法可以运行这个some method委托(不管传递了什么),并返回执行的时间跨度。

       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 回复  |  直到 16 年前
        1
  •  4
  •   Cecil Has a Name    16 年前

    严格地说,方法签名必须与委托指定的签名完全匹配(协变匹配除外)。但是,您可以创建一个 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()
        {
        }
    }
    

    虚拟方法分派具有与委托类似的延迟,并且比动态调用要好得多。

        2
  •  4
  •   Alfred Myers    16 年前

    将委托与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在运行时包含一个公司,但它的静态类型是object。

    现在我们知道了,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,将带有任何类型对象的数组传递给它,而不是公司类型的对象。

    当然,编译器不允许这样做。

    相反,您可以反转委托的类型和目标方法,例如:

    
    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);
    }
    

    然后它将编译,因为您将向接受任何类型对象的方法传递一个客户数组。

    结论: 参数不影响类型差异规则。

        3
  •  2
  •   Lasse V. Karlsen    16 年前

    匹配 params 参数是编译器的魔力,委托不存在这样的魔力。它将匹配一个方法,该方法在正确的位置有一个兼容类型的数组,但没有其他方法。

    因此,是的,您需要更改所有方法,或者使用匿名方法作为包装,如下所示:

    SomeMethod dlg = new SomeMethod(delegate(Object[] parameters)
    {
        InsertObjects((Company)parameters[0]);
    };