【问题标题】:Will Delegate with params keyword match any method?使用 params 关键字的 Delegate 会匹配任何方法吗?
【发布时间】:2009-08-30 22:25:31
【问题描述】:

我正在尝试完成以下事情:

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

【问题讨论】:

    标签: c# delegates


    【解决方案1】:

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

    Delegate with 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 在运行时包含了一个 Company,但它的静态类型是 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,向其传递一个包含任何类型对象的数组,而不是 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 不影响类型变化规则。

    【讨论】:

      【解决方案3】:

      匹配params 参数是编译器的魔法,而委托不存在这样的魔法。它将匹配在正确位置具有兼容类型数组的方法,但仅此而已。

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-26
        • 1970-01-01
        相关资源
        最近更新 更多