简体   繁体   English

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

[英]Will Delegate with params keyword match any method?

I'm trying to get the following thing done: 我正在努力完成以下事情:

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

That's my delegate. 那是我的代表。 And i have some method that will run this SomeMethod delegate (whatever's passed) and return me the timespan of execution. 我有一些方法将运行这个SomeMethod委托(无论传递什么)并返回执行的时间跨度。

   public TimeSpan BenchmarkMethod(SomeMethod someMethod, params object[] parameters)
    {
        DateTime benchmarkStart = DateTime.Now;

        someMethod(parameters);

        DateTime benchmarkFinish = DateTime.Now;
        return benchmarkFinish - benchmarkStart;
    }

Also i have some method: 我也有一些方法:

public abstract void InsertObjects (Company c);

So, i declare it: 所以,我宣布:

SomeMethod dlg = new SomeMethod(InsertObjects);
TimeSpan executionTime = BenchmarkMethod(dlg, c);

But it doesn't run, saying that No overload for 'InsertObjects' matches delegate 'TestFactory.MeasuringFactory.SomeMethod'. 但它没有运行,说'InsertObjects'没有重载匹配委托'TestFactory.MeasuringFactory.SomeMethod'。 Is there any way to do it?.. Or i should change all the methods of mine to accept params object[] as an argument?.. 有没有办法做到这一点?或者我应该改变我的所有方法来接受params对象[]作为参数?

Strictly no, the method signature must exactly match the signature specified by the delegate (except for covariant matching). 严格来说,方法签名必须与委托指定的签名完全匹配(协变匹配除外)。 However, you can create an object[] array and feed to Delegate.DynamicInvoke(object[] args) . 但是,您可以创建一个object[]数组并将其提供给Delegate.DynamicInvoke(object[] args)

Edit: 编辑:

If you have information about the method to be called, you can use MethodBase.GetParameters().Length to obtain the number of arguments, so you can correctly size the untyped argument array. 如果您有关于要调用的方法的信息,可以使用MethodBase.GetParameters().Length来获取参数的数量,这样您就可以正确调整无类型参数数组的大小。

For benchmarking, though, I think you are better off using an abstract base class that implements the necessary benchmarking ops: 但是,对于基准测试,我认为您最好使用实现必要的基准测试操作的抽象基类:

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()
    {
    }
}

Virtual method dispatches have comparable latency to delegates, and much better than dynamic invocation. 虚拟方法调度具有与委托相当的延迟,并且比动态调用更好。

Will Delegate with params keyword match any method? 委托与params关键字匹配任何方法?

No. They still have to respect type variance. 不, 他们仍然需要尊重类型差异。

params is only syntatic sugar for saying that from that point and beyond, all parameters of the call site are considered to be part of the same array on the method. params只是合成糖,因为说从那时起,呼叫站点的所有参数都被认为是该方法上同一阵列的一部分。

So, for a method defined as: 因此,对于定义为的方法:


TimeSpan BenchmarkMethod(SomeMethod someMethod, params Company[] parameters)

You can do: 你可以做:


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

but not: 但不是:


Company company1 = null;
object company3 = new Company();

BenchmarkMethod(dlg, company1, company3);

Because, although company3 contains a Company at runtime, it's static type is object. 因为,虽然company3在运行时包含公司,但它的静态类型是对象。

So now we know that params simply defines an array on a method, that allows you to use a more convenient syntax at the call site. 所以现在我们知道params只是在方法上定义一个数组,它允许你在调用站点使用更方便的语法。

Now let's go on with the real reason for your code not working as you expected: Type variance 现在让我们继续说明您的代码无法按预期工作的真正原因:键入方差

Your delegate is defined as: 您的代理人定义为:


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

and you target method as: 并将方法定位为:


public abstract void InsertObjects (Company c);

When invoking the delegate: 调用委托时:


SomeMethod dlg = new SomeMethod(InsertObjects);
TimeSpan executionTime = BenchmarkMethod(dlg, c);

You are essentialy saying you can call InsertObjects passing it an array with any type of object instead of an object of type Company. 您实际上是在说可以调用InsertObjects向它传递一个包含任何类型对象的数组,而不是类型为Company的对象。

That of course is not allowed by the compiler. 当然,编译器不允许这样做。

If instead, you invert the types of the delegate and the target method such as in: 相反,如果您反转委托的类型和目标方法,例如:


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

Then it will compile, because you'll be passing an array of Customer to a method that accepts any kind of object. 然后它将编译,因为您将把一个Customer数组传递给一个接受任何类型对象的方法。

Conclusion: params does not affect type variance rules. 结论: params不影响类型方差规则。

Matching params parameters is compiler magic, and no such magic exists for delegates. 匹配params参数是编译器魔术,并且代理人不存在这样的魔法。 It will match a method that has an array of a compatible type in the right position, but nothing else. 它将匹配一个方法,该方法在正确的位置具有兼容类型的数组,但没有别的。

So yes, you need to either change all your methods, or use anonymous methods as wrappers, like this: 所以是的,您需要更改所有方法,或者使用匿名方法作为包装器,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM