TL; DR:
Есть ли способ добавить абстрактный метод в базовый класс, который позволяет производным классам переопределять тип возврата метода, без использованиядженерики, и без использования ключевого слова new
?
Я работаю над разработкой некоторых пользовательских шаблонов для LLBLGen Pro.В процессе я отказываюсь изменять шаблоны по умолчанию, которые предлагает LLBLGen Pro, чтобы мой подход не переписывал файлы других людей, если они решили реализовать мои шаблоны.
Одна задача, над которой я начал работать(и добился хороших успехов) разрабатывает шаблон, который генерирует DTO для каждой сущности.В соответствии с этим одной из целей является предоставление моим сущностям метода ToDTO()
.В интересах общего программирования я решил определить этот метод в общем базовом классе, и именно здесь начинаются мои проблемы.
Имейте в виду, что цель определенияМетод ToDTO()
в базовом классе объясняется тем, что я пытаюсь создать общий репозиторий (например, с методом Fetch()
), который я бы хотел отработать от CommonEntityBase
, в отличие от конкретной сущности.
LLBLGen определяет свой класс CommonEntityBase
следующим образом:
public abstract partial class CommonEntityBase : EntityBase2 {
// LLBLGen-generated code
}
Первоначально я планировал добавить мой метод в другой частичный класс, например:
public abstract partial class CommonEntityBase {
public abstract CommonDTOBase ToDto();
}
Я думал, что унаследованные классы смогут определить возвращаемый тип в своих методах как тип, производный от возвращаемого типа базового класса, например:
public partial class PersonEntity : CommonEntityBase {
public override PersonDTO ToDto(){ return new PersonDTO(); }
}
, но Я был не прав .
Моя вторая попытка была определить класс с использованием обобщений, как таковых:
public abstract partial class CommonEntityBase<T> : CommonEntityBase
where T : CommonDTOBase {
public abstract T ToDto();
}
Достаточно простоВсе, что мне нужно сделать, - это чтобы мои сгенерированные классы сущностей наследовали от этой новой базы сущностей.Только одна оговорка.Поскольку я не хочу перезаписывать шаблоны LLBLGen, мы вернулись к частичным классам.
У отдельных объектов LLBLGen есть следующее определение:
public partial class PersonEntity : CommonEntityBase {
// LLBLGen-generated code
}
И в этом заключается моя проблема.Чтобы мой метод работал, мне нужно было бы создать свой собственный частичный класс с таким определением:
public partial class PersonEntity : CommonEntityBase<PersonDTO> {
public override PersonDTO ToDto(){ return new PersonDTO(); }
}
Конечно, это невозможно, потому что как я теперь знаю ,
Все части [частичного класса], которые задают базовый класс , должны согласовываться , но части, которые опускают базовый класс, все еще наследуют базовый тип.
Третья вещь, которую я собирался попробовать, это просто переопределить определение функции базового класса с помощью ключевого слова new :
public abstract partial class CommonEntityBase {
public virtual CommonDTOBase ToDto(){ return null; }
}
public partial class PersonEntity : CommonEntityBase {
public new PersonDTO ToDto(){ return new PersonDTO(); }
}
Однако это побеждаетцель моего подхода полностью, так как я хочу иметь доступ к методу PersonEntity
ToDTO()
, когда он приведен как CommonEntityBase
.При таком подходе выполнение:
CommonEntityBase e = new PersonEntity();
var dto = e.ToDto();
приведет к тому, что dto
будет нулевым, чего я не хочу.
Я встречал различных links обсуждают мой первый подход и почему он не работает, и обычно указывают на мой общий подход как решение в общем смысле.Однако в моей ситуации генерики не работают.
Все это, чтобы спросить, возможно ли то, что я пытаюсь выполнить.
Есть ликакой-нибудь способ добавить абстрактный метод к базовому классу, который позволяет производным классам переопределять тип возвращаемого значения метода, без использования обобщений и без использования ключевого слова new
?
Или, возможно,Я подхожу к этому с неправильной точки зрения, и есть какая-то другая техника, которая может решить мои проблемы?
РЕДАКТИРОВАТЬ
Вотсценарий использования того, что я хотел бы выполнить с сущностями, используя подход Поргеса :
public class BaseRepository<D,E> where D : CommonDTOBase where E : CommonEntityBase,new
public D Get(Guid id){
var entity = new E();
entity.SetId(id);
// LLBLGen adapter method; populates the entity with results from the database
FetchEntity(entity);
// Fails, as entity.ToDto() returns CommonDTOBase, not derived type D
return entity.ToDto();
}
}