Ce que vous devez retenir, c'est que la résolution dynamique essentiellement le même processus que la statique de la résolution, mais au moment de l'exécution. Tout ce qui ne pouvait pas être résolu par le CLR ne sera pas résolu par le DLR.
Prenons ce petit programme, inspiré par la vôtre, et qui n'utilise pas dynamique du tout:
namespace ConsoleApplication38 {
public interface IActualInterface {
void Store(object entity);
}
public interface IExtendedInterface : IActualInterface {
}
public class TestInterface : IExtendedInterface {
public void Store(object entity) {
}
}
public abstract class ActualClass {
public abstract void Store(object entity);
}
public abstract class ExtendedClass : ActualClass {
}
public class TestClass : ExtendedClass {
public override void Store(object entity) {
}
}
class Program {
static void TestInterfaces() {
IActualInterface actualTest = new TestInterface();
IExtendedInterface extendedTest = new TestInterface();
TestInterface directTest = new TestInterface();
actualTest.Store(null);
extendedTest.Store(null);
directTest.Store(null);
}
static void TestClasses() {
ActualClass actualTest = new TestClass();
ExtendedClass extendedTest = new TestClass();
TestClass directTest = new TestClass();
actualTest.Store(null);
extendedTest.Store(null);
directTest.Store(null);
}
static void Main(string[] args) {
TestInterfaces();
TestClasses();
}
}
}
Tout compile bien. Mais ce que fait le compilateur vraiment générer? Nous allons voir à l'aide de ILdasm.
Pour les interfaces:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.IActualInterface::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.IActualInterface::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.TestInterface::Store(object)
Nous pouvons voir ici que le compilateur C# génère toujours des appels de l'interface ou de la classe dans laquelle la méthode est définie. IActualInterface
a une méthode logement pour le Magasin de sorte qu'il est utilisé pour l' actualTest.Store
. IExtendedInterface
n'est pas le cas, IActualInterface
est utilisé pour l'appel. TestInterface
définit une nouvelle méthode de Magasin, à l'aide de l' newslot
IL modificateur, effectivement l'attribution d'un nouveau logement dans la vtable pour cette méthode, il est donc utilisé directement depuis directTest
est de type TestInterface
.
Pour les classes:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
Pour les 3 types différents, le même appel est généré en raison de la méthode de logement est défini sur ActualClass.
Nous allons maintenant voir ce que nous obtenons si nous écrivons le IL de nous-mêmes, en utilisant le type que nous voulons plutôt que de laisser le compilateur C# qui le choisissent pour nous. J'ai modifié le IL ressemble à ceci:
Pour les interfaces:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.IActualInterface::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.IExtendedInterface::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.TestInterface::Store(object)
Pour les classes:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.ExtendedClass::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.TestClass::Store(object)
Le programme compile bien avec ILasm. Cependant, il ne parvient pas à passer peverify et se bloque lors de l'exécution avec l'erreur suivante:
Exception Non Gérée:
Système.MissingMethodException: Méthode
pas trouvé: "Void
ConsoleApplication38.IExtendedInterface.Magasin(Le Système.Objet)'.
au
ConsoleApplication38.Programme.TestInterfaces()
au
ConsoleApplication38.Programme.Main(String[]
args)
Si vous supprimez cette invalide appel, les classes dérivées appels fonctionne très bien sans aucune erreur. Le CLR est en mesure de résoudre à la base de la méthode de la dérivée de type d'appel. Cependant, les interfaces ont pas de véritable représentation dans l'exécution, et le CLR n'est pas en mesure de résoudre l'appel de méthode à partir de l'interface étendue.
En théorie, le compilateur C# pourrait émettre l'appel directement à la bonne classe spécifiée dans le runtime. Il permettrait d'éviter les problèmes sur les classes moyennes appelle comme on le voit sur Eric Lippert du blog. Cependant, comme l'ont démontré, ce n'est pas possible pour des interfaces.
Revenons à la DLR. Il résout la méthode exactement de la même manière que le CLR. Nous avons vu que l' IExtendedInterface.Store
ne pouvait pas être résolu par le CLR. Le DLR ne peut pas non plus! C'est totalement masqué par le fait que le compilateur C# émet le droit d'appel, il faut donc toujours être prudent lors de l'utilisation d' dynamic
, sauf si vous savez parfaitement comment cela fonctionne dans le CLR.