2010-06-26 68 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的確切類型?