我做了一些测试(在 .Net 3.5 中......稍后我将使用 .Net 4 在家里检查)。
事实上:
获取对象作为接口然后执行方法比从方法获取委托然后调用委托要快。
考虑到变量已经是正确的类型(接口或委托)并且简单地调用它使委托获胜。
由于某种原因,通过接口方法(可能通过任何虚拟方法)获取委托要慢得多。
而且,考虑到在某些情况下我们无法预先存储委托(例如在 Dispatches 中),这可能证明接口更快的原因。
结果如下:
要获得真正的结果,请在发布模式下编译它并在 Visual Studio 之外运行它。
检查直接调用两次
00:00:00.5834988
00:00:00.5997071
检查接口调用,每次调用都获取接口
00:00:05.8998212
检查接口调用,获取一次接口
00:00:05.3163224
检查操作(委托)调用,在每次调用时获取操作
00:00:17.1807980
检查操作(委托)调用,获取一次操作
00:00:05.3163224
通过接口方法检查操作(委托),同时获取
每次通话
00:03:50.7326056
通过接口方法检查操作(委托),获取
接口一次,每次调用时的委托
00:03:48.9141438
通过接口方法检查操作(委托),一次获得两个
00:00:04.0036530
如您所见,直接调用非常快。
之前存储接口或委托,然后只调用它真的很快。
但是必须获得委托比获得接口要慢。
必须通过接口方法(或虚拟方法,不确定)获得委托真的很慢(比较将对象作为接口的 5 秒与执行相同操作的近 4 分钟)。
生成这些结果的代码在这里:
using System;
namespace ActionVersusInterface
{
public interface IRunnable
{
void Run();
}
public sealed class Runnable:
IRunnable
{
public void Run()
{
}
}
class Program
{
private const int COUNT = 1700000000;
static void Main(string[] args)
{
var r = new Runnable();
Console.WriteLine("To get real results, compile this in Release mode and");
Console.WriteLine("run it outside Visual Studio.");
Console.WriteLine();
Console.WriteLine("Checking direct calls twice");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
r.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
r.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking interface calls, getting the interface at every call");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
IRunnable interf = r;
interf.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking interface calls, getting the interface once");
{
DateTime begin = DateTime.Now;
IRunnable interf = r;
for (int i = 0; i < COUNT; i++)
{
interf.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) calls, getting the action at every call");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
Action a = r.Run;
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) calls, getting the Action once");
{
DateTime begin = DateTime.Now;
Action a = r.Run;
for (int i = 0; i < COUNT; i++)
{
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) over an interface method, getting both at every call");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
IRunnable interf = r;
Action a = interf.Run;
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) over an interface method, getting the interface once, the delegate at every call");
{
DateTime begin = DateTime.Now;
IRunnable interf = r;
for (int i = 0; i < COUNT; i++)
{
Action a = interf.Run;
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) over an interface method, getting both once");
{
DateTime begin = DateTime.Now;
IRunnable interf = r;
Action a = interf.Run;
for (int i = 0; i < COUNT; i++)
{
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.ReadLine();
}
}
}