J'ai fait quelques tests (en .Net 3.5... plus tard, je vais vérifier à la maison à l'aide .Net 4).
Le fait est:
Obtenir un objet comme une interface, puis de l'exécution de la méthode est plus rapide que l'obtention d'un délégué d'une méthode, puis l'appel de la déléguer.
Compte tenu de la variable est déjà dans le type de droit (interface ou de son délégué) et de la simple invocation, il rend le délégué gagner.
Pour quelque raison, l'obtention d'un délégué sur une méthode d'interface (peut-être sur toute méthode virtuelle) est BEAUCOUP plus lente.
Et, considérant qu'il y a des cas, quand nous simple ne peut pas pré-stocker les délégué (comme dans les Dépêches, par exemple), qui peuvent justifier pourquoi les interfaces sont plus rapides.
Voici les résultats:
Pour obtenir de vrais résultats, le compiler en mode Release et l'exécuter en dehors de Visual Studio.
La vérification des appels directs à deux reprises
00:00:00.5834988
00:00:00.5997071
La vérification des appels d'interface, l'obtention de l'interface à chaque appel
00:00:05.8998212
La vérification des appels d'interface, l'obtention de l'interface une fois
00:00:05.3163224
Action de vérification (délégué) des appels, passer à l'action à chaque appel
00:00:17.1807980
Action de vérification (délégué) des appels, passer à l'Action une fois
00:00:05.3163224
Action de vérification (délégué) sur une méthode de l'interface, les deux à
chaque appel
00:03:50.7326056
Action de vérification (délégué) sur une méthode de l'interface, l'obtention de la
interface une fois, le délégué à chaque appel
00:03:48.9141438
Action de vérification (délégué) sur une méthode de l'interface, les deux fois
00:00:04.0036530
Comme vous pouvez le voir, les appels directs sont vraiment rapide.
Le stockage de l'interface ou son délégué avant, et ensuite seulement l'appel, il est vraiment très rapide.
Mais d'avoir à obtenir un délégué est plus lent que d'avoir à obtenir une interface.
D'avoir à obtenir un délégué sur une méthode d'interface (ou de méthode virtuelle, pas sûr) est très lent (comparer les 5 secondes de l'obtention d'un objet comme une interface à la près de 4 minutes de faire de même pour obtenir l'action).
Le code qui a généré ces résultats c'est ici:
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();
}
}
}