2010-06-26 69 views
0

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(); } 
} 

但是I was wrong


我的第二次尝试使用泛型定义类,因为这样的:

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(); } 
} 

当然,这是不可能的,因为,as I now know

所有的指定基类的[部分类]部分必须同意,但省略基类的部分仍继承基类型。


我要去尝试简单地重写基类的函数定义与new关键字第三件事:

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

public partial class PersonEntity : CommonEntityBase { 
    public new PersonDTO ToDto(){ return new PersonDTO(); } 
} 

然而,这完全违背了我的做法的目的,因为我希望能够访问PersonEntityToDTO()方法,当它投射为CommonEntityBase时。通过这种方法,这样做的:

CommonEntityBase e = new PersonEntity(); 
var dto = e.ToDto(); 

会导致dto是空的,我不想要的。


我遇到variouslinks讨论我的第一种方法,为什么它不会工作,通常指着我的通用方法是在一般意义上的解决方案。但是,在我的情况下,仿制药似乎不起作用。


所有这些问是否我想要完成的是可能的。

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

或者我可能从错误的角度来解决这个问题,还有其他技术可以解决我的问题吗?


编辑

这里有一个用例为想什么,我与实体来完成,以Porges's方法:

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(); 
    } 
} 
+0

你似乎有一些'partial'类的概念问题。没有魔法参与;我认为最好的方法是编译器在编译之前将所有为分部类定义的代码填充到一个类定义中。 – porges 2010-06-27 03:35:56

+0

Google“协变返回类型”。 – 2010-06-27 13:06:00

回答

0

我不知道LLBLGEN ,但我相信你可以通过引入一个接口来保存类型参数来解决你的问题:

public interface DTOProvider<T> where T : CommonDTOBase { 
    public T ToDTO(); 
} 

然后为实体类,这样做:

public partial class PersonEntity : CommonEntityBase, DTOProvider<PersonDTO> { 
    public PersonDTO ToDto() { return new PersonDTO(); } 
} 

由于部分类可以引入不同的接口,这个工程。唯一的忧伤,就是铸造需要通过基本类型,以获得进入方法:

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

当然,你可以调用ToDTO的情况下直接投时,你有实体派生类型之一的参考:

public void DoSomethingWithPersonDTO(PersonEntity entity) 
{ 
    PersonDTO dto = entity.ToDTO(); 
    ... 
} 

如果您使用的是.NET Framework 4中,你可以使用通用的差异,使DTOProvider接口更容易从刚刚关心通过声明DTO类型协与CommonDTOBase工作代码使用方法:

public interface DTOProvider<out T> where T : CommonDTOBase { 
    public T ToDTO(); 
} 

(注意“出”。)然后你DoSomethingWithDTO方法不需要类型参数:

public void DoSomethingWithDTO(CommonBaseEntity entity) { 
    CommonDTOBase dto = ((DTOProvider<CommonDTOBase>) entity).ToDTO(); 
    ... 
} 

这是很有诱惑力的尝试,并在CommonBaseEntity部分类声明: CommonBaseEntity, DTOProvider<T>。不幸的是,这是行不通的,因为当部分定义被合并时,类型参数被继承,并且你的CommonBaseEntity类型最终成为一个泛型类型,看起来像是你首先把你绑定到绑定中的东西。

+0

通过这种方法,'CommonBaseEntity'在哪里得到了ToDto()'的定义?如果它继承使用':DTOProvider ',那么我们会遇到我最初的问题:无法更改返回类型,如果它继承使用':DTOProvider ',那么我们必须将泛型合并到'CommonBaseEntity'中。 – cmptrgeekken 2010-06-27 00:27:28

4

相反的:

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(); } 
} 

我认为这是对面向对象的代码更地道。您是否有理由需要知道DTO的确切类型?