Предположим, у меня есть библиотека версии 1.0.0 со следующим содержимым:
public class Class1
{
public virtual void Test()
{
Console.WriteLine( "Library:Class1 - Test" );
Console.WriteLine( "" );
}
}
public class Class2 : Class1
{
}
и я ссылаюсь на эту библиотеку в консольном приложении со следующим содержимым:
class Program
{
static void Main( string[] args )
{
var c3 = new Class3();
c3.Test();
Console.ReadKey();
}
}
public class Class3 : ClassLibrary1.Class2
{
public override void Test()
{
Console.WriteLine("Console:Class3 - Test");
base.Test();
}
}
Запуск программы выведет следующее:
Console:Class3 - Test
Library:Class1 - Test
Если я создаю новую версию библиотеки версии 2.0.0, выглядя так:
public class Class1
{
public virtual void Test()
{
Console.WriteLine( "Library:Class1 - Test V2" );
Console.WriteLine( "" );
}
}
public class Class2 : Class1
{
public override void Test()
{
Console.WriteLine("Library:Class2 - Test V2");
base.Test();
}
}
и скопируйте эту версию в папку bin, содержащую мою консольную программу, и запустите ее, результаты:
Console:Class3 - Test
Library:Class1 - Test V2
I.e, метод Class2.Test никогда не выполняется, вызов base.Test в Class3.Test, похоже, связан с Class1.Test, поскольку Class2.Test не существовал при компиляции консольной программы. Это было очень удивительно для меня и может быть большой проблемой в ситуациях, когда вы развертываете новые версии библиотеки без перекомпиляции приложений.
Есть ли у кого-нибудь еще опыт?
Есть ли хорошие решения?
Это заставляет искушать добавлять пустые переопределения, которые просто называет базу, если мне нужно добавить код на этом уровне в будущем...
Edit:
Кажется, установлено, что вызов связан с первым существующим базовым методом во время компиляции. Интересно, почему. Если я создам свою консольную программу со ссылкой на версию 2 моей библиотеки (это должно означать, что вызов скомпилирован для вызова Class2.Test), а затем замените DLL в папке bin на версию 1, результат будет, как и ожидалось:
Console:Class3 - Test
Library:Class1 - Test
Таким образом, не существует ошибки во время выполнения, если Class2.Test не существует. Почему базовый вызов не был скомпилирован для вызова Class2.Test в первую очередь?
Было бы интересно получить комментарий от Эрика Липперта или кого-то еще, кто работает с компилятором...