C # Generics Inheritance - PullRequest
       17

C # Generics Inheritance

3 голосов
/ 28 октября 2010

У меня есть следующий класс

public class AccountingBase<TItemType> where TItemType : AccountingItemBase

И в моем AccountingItemBase у меня есть следующее свойство:

public virtual AccountingBase<AccountingItemBase> Parent { get; set; }

в моей Бухгалтерии, я пытаюсь сделать следующее

item.Parent = this;

Логически это должно работать, так как TItemType наследуется от AccountingItemBase, но вместо этого я получаю следующую ошибку:

> Error 1 Cannot implicitly convert type
> 'TGS.MySQL.DataBaseObjects.AccountingBase<TItemType>'
> to
> 'TGS.MySQL.DataBaseObjects.AccountingBase<TGS.MySQL.DataBaseObjects.AccountingItemBase>'

Как я могу установить родительское свойство дочерних свойств для себя (внутри родительского класса)

Ответы [ 2 ]

6 голосов
/ 28 октября 2010

Нет, ваша интуиция неверна. Это не должно работать, потому что универсальные классы не являются вариантами в .NET.

То, что TItemType наследуется от AccountingItemBase, не означает, что AccountingBase<TItemType> наследуется от AccountingBase<AccountingItemBase>. Предположим, что AccountingBase<TItemType> имеет поле типа TItemType. Тогда, если ваша интуиция была правильной, вы могли бы написать:

AccountingBase<SomeSubtype> x = new AccountingBase<SomeSubtype>();
AccountingBase<AccountingItemBase> y = x;
y.SomeField = new OtherSubtype();

Это явно нарушит безопасность типов, потому что если рассматривать это как AccountingBase<SomeSubtype>, поле должно иметь тип SomeSubtype, но вы поместили туда значение типа OtherSubtype!

По сути, общая дисперсия - сложная тема.

Я предлагаю вам прочитать длинный и подробный пост в блоге Эрика Липперта для получения дополнительной информации. Или у меня есть видео с NDC 2010 , которое может оказаться полезным. В основном в .NET 4 есть некоторая общая дисперсия, но она ограничена.

Теперь, что вы можете сделать в вашей ситуации:

  • Вы можете создать неуниверсальный базовый класс, от которого наследуется AccountingBase. Это, наверное, лучшая идея. Затем сделайте тип свойства Parent неуниверсальным типом.
  • Вы можете сделать AccountingBase родовым как для себя, так и для его родителя ... но это в конечном итоге приведет к проблемам рекурсии, эффективно ...
1 голос
/ 28 октября 2010

В дополнение к опциям Джона вы могли бы:

  • Создать интерфейс IAccountingBase, который предоставляет только ограниченный доступ, необходимый для выполнения своей работы AccountingItemBase (аналогично неуниверсальному)базовый класс, но дополнительно абстрагированный.)

  • Перестройте ваш код, чтобы AccountingItemBase не нуждался в родительской ссылке для своей работы.Мой опыт показывает, что циклические зависимости (владелец знает об элементах, которые знают о владельце) являются симптомом схемы, в которой экземпляры Child принимают на себя слишком много обязанностей.Иногда это можно обойти, перенеся функциональность в Родитель или переместив его в классы более высокого уровня, которые выполняют сложные операции над несколькими Предметами в контексте одного Родителя, устраняя необходимость для каждого Предмета иметь родительскую ссылку.Например, если ваши Предметы предоставляют функции, связанные с выверкой Учетной записи, вы можете иметь класс AccountReconciler, а не помещать функции в Предметы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...