Hatırlamanız gereken şey, dinamik çözümün temelde statik çözünürlükle aynı işlemi gerçekleştirmesidir, ancak çalışma zamanında. CLR tarafından çözülemeyen herhangi bir şey DLR tarafından çözülmeyecektir.
seninkinden esinlenerek bu küçük program alalım ve bu hiç de dinamik kullanmaz:
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();
}
}
}
Her şey iyi derler. Ama derleyici gerçekten ne üretti? ILdasm kullanarak görelim. arabirimler için
:
// 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)
Biz C# derleyicisi daima yöntemi tanımlanır arayüzü veya sınıf için çağrılarını oluşturduğu burada görebilirsiniz. IActualInterface
'un Store için bir yöntem yuvası vardır, bu nedenle actualTest.Store
için kullanılır. IExtendedInterface
, arama için IActualInterface
kullanmıyor. TestInterface
, directTest
türünde TestInterface
türünde olduğundan, doğrudan bu yöntem için vtable'da yeni bir yuva atayarak, newslot
IL değiştiricisini kullanan yeni bir yöntem deposunu tanımlar. sınıfları için
: yöntem yuvası ActualClass tanımlı olduğu için, 3 farklı tipleri için
// 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)
, aynı çağrı oluşturulur.
Şimdi IL'leri kendimiz yazıp, C# derleyicisini bizim için seçmesine izin vermek yerine istediğimiz türü kullanarak yazdığımızı görelim. Böyle görünmek IL değiştirdik:
arayüzleri için:
// 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)
sınıflar için:
// 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)
programı ILASM ile iyi derler. Ancak aşağıdaki hata ile zamanında peverify ve çöker geçemeyen: Bu geçersiz çağrıyı kaldırırsanız
Unhandled Exception: System.MissingMethodException: Method not found: 'Void ConsoleApplication38.IExtendedInterface.Store(System.Object)'. at ConsoleApplication38.Program.TestInterfaces() at ConsoleApplication38.Program.Main(String[] args)
, türetilmiş sınıfları çağrılar herhangi bir hata olmadan iyi çalışır. CLR, türetilmiş tip çağrısından temel yöntemi çözebilir.Ancak, arabirimlerin çalışma zamanında gerçek bir temsili yoktur ve CLR, yöntem çağrısını genişletilmiş arabirimden çözemez.
Teoride, C# derleyicisi çağrıyı doğrudan çalışma zamanında belirtilen doğru sınıfa verebilir. Eric Lippert's blog'da görüldüğü gibi orta sınıf çağrıları ile ilgili sorunlardan kaçınacaktır. Ancak gösterildiği gibi, bu arayüzler için mümkün değildir.
DLR'ye dönelim. Yöntemi, CLR ile tam olarak aynı şekilde giderir. IExtendedInterface.Store
'un CLR tarafından çözülemediğini gördük. DLR de yapamaz! Bu, C# derleyicisinin doğru çağrıyı yayınlayacağı gerçeği tarafından tamamen gizlidir, bu nedenle CLR'de nasıl çalıştığını tam olarak bilmiyorsanız, dynamic
kullanırken her zaman dikkatli olun.
Bu çalışma Raven'de buldunuz değil mi? –
@Chris emin yaptım! –