C# 在没有泛型的派生类中重新定义方法返回类型

C# 在没有泛型的派生类中重新定义方法返回类型,c#,inheritance,partial-classes,llblgen,C#,Inheritance,Partial Classes,Llblgen,TL;医生: 是否有某种方法可以将抽象方法添加到基类,从而允许派生类重写方法的返回类型,而不使用泛型,也不使用new关键字 我正在为LLBLGen Pro开发一些自定义模板。在这个过程中,我拒绝更改llblgenpro提供的默认模板,这样,如果其他人选择实现我的模板,我的方法就不会覆盖他们的文件 我已经开始着手(并取得了良好进展)的一项任务是开发一个为每个实体生成DTO的模板。沿着这些思路,一个目标是为我的实体提供一个ToDTO()方法。出于对泛型编程的兴趣,我决定在一个公共基类中定义这个方法

TL;医生:

是否有某种方法可以将抽象方法添加到基类,从而允许派生类重写方法的返回类型,而不使用泛型,也不使用
new
关键字


我正在为LLBLGen Pro开发一些自定义模板。在这个过程中,我拒绝更改llblgenpro提供的默认模板,这样,如果其他人选择实现我的模板,我的方法就不会覆盖他们的文件

我已经开始着手(并取得了良好进展)的一项任务是开发一个为每个实体生成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 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();
}
这就是我的问题所在。为了使方法正常工作,我必须使用以下定义创建自己的分部类:

public partial class PersonEntity : CommonEntityBase {
   // LLBLGen-generated code
}
public partial class PersonEntity : CommonEntityBase<PersonDTO> {
   public override PersonDTO ToDto(){ return new PersonDTO(); }
}
但是,这完全违背了我的方法的目的,因为我希望在将
PersonEntity
转换为
CommonEntityBase
时能够访问
PersonEntity
ToDTO()
方法。使用此方法,请执行以下操作:

CommonEntityBase e = new PersonEntity();
var dto = e.ToDto();
将导致
dto
为null,这是我不希望看到的


我曾经讨论过我的第一种方法,以及为什么它不起作用,并且通常将我的通用方法作为一般意义上的解决方案。然而,在我的情况下,泛型似乎不起作用


所有这些都是为了问我是否有可能实现我的目标

是否有办法向基类添加一个抽象方法,允许派生类重写该方法的返回类型,而不使用泛型,也不使用
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();
    }
}
public class BaseRepository其中D:CommonDTOBase其中E:CommonEntityBase,新建
公共数据获取(Guid id){
var entity=newe();
实体.SetId(id);
//LLBLGen适配器方法;使用数据库中的结果填充实体
实体(实体);
//失败,因为entity.ToDto()返回CommonDTOBase,而不是派生类型D
返回entity.ToDto();
}
}

我不知道LLBLGen,但我相信通过引入一个保存类型参数的接口,您可以通过这种方式解决问题:

public interface DTOProvider<T> where T : CommonDTOBase {
    public T ToDTO();
}
public void DoSomethingWithDTO(CommonBaseEntity entity) {
    CommonDTOBase dto = ((DTOProvider<CommonDTOBase>) entity).ToDTO();
    ...
}
如果您使用的是.NET Framework 4,则可以通过声明DTO类型协变变量,从只关心使用CommonDTOBase的代码中使用generic variance使DTOProvider接口更易于使用:

public interface DTOProvider<out T> where T : CommonDTOBase {
    public T ToDTO();
}
公共接口DTOProvider,其中T:CommonDTOBase{
公共ToDTO();
}
(注意“out”。)那么DoSomethingWithDTO方法不需要类型参数:

public interface DTOProvider<T> where T : CommonDTOBase {
    public T ToDTO();
}
public void DoSomethingWithDTO(CommonBaseEntity entity) {
    CommonDTOBase dto = ((DTOProvider<CommonDTOBase>) entity).ToDTO();
    ...
}
public void DoSomethingWithDTO(CommonBaseEntity){
CommonDTOBase dto=((DTOProvider)实体).ToDTO();
...
}

尝试在CommonBaseEntity分部类上声明
:CommonBaseEntity,DTOProvider
,这很有诱惑力。不幸的是,这不起作用,因为当部分定义被合并时,类型参数被保留下来,您的CommonBaseEntity类型最终成为泛型类型,这看起来就像是让您首先陷入绑定的原因。

我不知道LLBLGen,但我相信您可以通过这种方式解决问题,通过引入一个接口来保存类型参数:

public interface DTOProvider<T> where T : CommonDTOBase {
    public T ToDTO();
}
public void DoSomethingWithDTO(CommonBaseEntity entity) {
    CommonDTOBase dto = ((DTOProvider<CommonDTOBase>) entity).ToDTO();
    ...
}
如果您使用的是.NET Framework 4,则可以通过声明DTO类型协变变量,从只关心使用CommonDTOBase的代码中使用generic variance使DTOProvider接口更易于使用:

public interface DTOProvider<out T> where T : CommonDTOBase {
    public T ToDTO();
}
公共接口DTOProvider,其中T:CommonDTOBase{
公共ToDTO();
}
(注意“out”。)那么DoSomethingWithDTO方法不需要类型参数:

public interface DTOProvider<T> where T : CommonDTOBase {
    public T ToDTO();
}
public void DoSomethingWithDTO(CommonBaseEntity entity) {
    CommonDTOBase dto = ((DTOProvider<CommonDTOBase>) entity).ToDTO();
    ...
}
public void DoSomethingWithDTO(CommonBaseEntity){
CommonDTOBase dto=((DTOProvider)实体).ToDTO();
...
}
尝试在CommonBaseEntity分部类上声明
:CommonBaseEntity,DTOProvider
,这很有诱惑力。不幸的是,这不起作用,因为当部分定义被合并时,类型参数被保留下来,您的CommonBaseEntity类型最终成为泛型类型,这看起来就像是让您首先进入绑定的原因。

而不是:

public abstract partial class CommonEntityBase {
    public abstract CommonDTOBase ToDto();
}

public partial class PersonEntity : CommonEntityBase {
    public override PersonDTO ToDto(){ return new PersonDTO(); }
}
为什么不返回这样的DTO:

public abstract partial class CommonEntityBase {
    public abstract CommonDTOBase ToDto();
}

public partial class PersonEntity : CommonEntityBase {
    // changed PersonDTO to CommonDTOBase
    public override CommonDTOBase ToDto(){ return new PersonDTO(); }
}
我认为这对于OO代码来说更为惯用。您需要知道DTO的确切类型有什么原因吗?

而不是:

public abstract partial class CommonEntityBase {
    public abstract CommonDTOBase ToDto();
}

public partial class PersonEntity : CommonEntityBase {
    public override PersonDTO ToDto(){ return new PersonDTO(); }
}
为什么不返回这样的DTO:

public abstract partial class CommonEntityBase {
    public abstract CommonDTOBase ToDto();
}

public partial class PersonEntity : CommonEntityBase {
    // changed PersonDTO to CommonDTOBase
    public override CommonDTOBase ToDto(){ return new PersonDTO(); }
}

我认为这对于OO代码来说更为惯用。您需要知道DTO的确切类型有什么原因吗?

使用这种方法,
CommonBaseEntity
从何处获得其对
ToDto()的定义?如果它使用
:DTOProvider
继承,那么我们将遇到无法更改返回类型的原始问题