Задача конечно жесть, действительно очень сложно понять конечную цель ваших манипуляций (а мотивацию для чего вы это делаете). Но немного теории на счет того, что тут происходит.
Есть AutoCommon и есть ряд наследников У AutoCommon есть свойство DSV, и у AutoA мы снова видим определение свойства DSV. В этот момент, компилятор неявно считает, что это абсолютно новое свойство, никак не связанное с родительским (каждый остается при своем свойстве). То есть то, что написано у вас на самом деле выглядит так
public class autoA : autoCommon{
public autoA(){
this.dvs = new dvsDizel();
}
public new dvsDizel dvs {get;set;}
}
Теперь идем в конструктор и понимаем, что объект создается только для DSV, который объявлен в дочернем классе. В родительском он как был пустой, таким и остается, о нем мы ничего не говорили.
Теперь когда мы делаем так:
AutoCommon auto = new AutoA();
WriteLine(auto.dsv.a);
Что мы видим? Правильно, ничего. Почему? Да потому что мы пытаемся обратиться к свойству, которое принадлежит родительскому классу, а мы его и не создавали никогда (точнее экземпляр объекта для свойства), мы создавали свойство дочернего объекта.
Перепишем пример так:
public class autoA : autoCommon{
public autoA(){
base.dvs = new dvsDizel();
}
public new dvsDizel dvs {get;set;}
}
Теперь мы создаем экземпляр объекта не для дочернего объекта, а именно для родителя.
После этого пример выше, выведет нам то, что вы видимо хотели, то есть строку с текстом.
НО при таком вызове:
AutoA auto = new AutoA();
WriteLine(auto.dsv.a);
Вы опять получите эксепшен с null. Почему ? Да потому что вы обращаетесь к свойству уже дочернего объекта, которое в этот раз мы оставили пустым)
Итого: вы имете 2 свойства в дочернем объекте (родительское и "свое") с одинаковым именем. Чтобы обратиться к родительскому используете base.* , чтобы обратиться к своему можно явно через this.*, либо this можно опустить.
public class autoA : autoCommon{
public autoA(){
base.dvs = new dvsDizel();
this.dvs = base.dsv;
}
public new dvsDizel dvs {get;set;}
}
В данном варианте они теперь ссылаются на один и тот же объект, но обращаясь по родительскому типу данных вы сможете получать общие методы dsv, а если сделаете приведение типов к конкретному классу AutoA, то сможете вызывать методы DvsDizel.