2017-03-02 176 views
0

我有兩個接口:實現抽象/接口方法

public interface IController 
{ 
    void doSomething(IEntity thing); 
} 

public interface IEntity { ... } 

一個示例實現將是:

public class ControllerImplA : IController 
{ 
    public void doSomething(IEntity entity) 
    { 
     EntityImplA entityForA = (EntityImplA)entity; 
     ... 
    } 
} 

public class EntityImplA : IEntity { ... } 

ControllerImplA.doSomething()entity參數將始終爲EntityImplA。同樣,ControllerImplB.doSomething()entity參數將始終爲EntityImplB,其他實現等等。

有沒有辦法避免在我當前的代碼中使用向下轉換?換句話說,我想要做這樣的事情:

public class ControllerImplA : IController 
{ 
    public void doSomething(EntityImplA entity) { ... } 
} 

沒有修改接口?那麼如果使用抽象父類而不是接口呢?

+3

「有沒有辦法避免使用向下轉換」使用泛型。 「沒有修改接口」呃... – BoltClock

+1

是否有一個原因,你可以改變你的接口到一個抽象類,但不能修改接口本身? – HimBromBeere

+2

如果你可以用抽象類替換接口,我想你可以修改它們來使用泛型。 – Evk

回答

3

你想使用泛型。修改接口是使這種清潔的唯一方法:

public interface IController<T> where T : IEntity 
{ 
    void doSomething(T thing); 
} 

然後:

public class ControllerImplA : IController<EntityImplA> 
{ 
    public void doSomething(EntityImplA entity) 
    { 
     ... 
    } 
} 

但是,如果你真的無法改變的接口,例如它是由第三方庫提供的,那麼@dasblinkenlight的解決方法就像你將要獲得的一樣乾淨。

+1

「不修改接口」...? – HimBromBeere

+0

嗯......好點。第一次沒有看到 - 是編輯過的,還是我錯過了它?無論哪種方式,這是唯一有意義的方法。 – Baldrick

+0

接受此。對不起,如果它聽起來令人困惑,但是當我說我不想混淆接口時,我的意思是我並不是真的想修改方法的參數類型來硬編碼特定實現的類型,只是爲了移除向下轉換。我很喜歡改變抽象類而不是界面......我想你可以說我只是不理解這些東西。花了一個小時,試圖把我的問題也寫成文字。 – thegreatjedi

2

如果在接口上沒有控制,實現它在與一類參數指定實體類型的通用抽象類,像這樣:

public interface IController { 
    void DoSomething(IEntity thing); 
} 

public interface IEntity { ... } 

abstract class AbstractController<TEntity> : IController where TEntity : IEntity { 
    public void DoSomething(IEntity e) { 
     // Forward the call to an abstract method with more specific type 
     DoSomethingImpl((TEntity)e); 
    } 
    // Subclasses need to implement this method instead of the interface method: 
    protected abstract void DoSomethingImpl(TEntity e); 
} 

現在,您的實現可以通過特定的子類從AbstractController派生,像這樣:

public class ControllerImplA : AbstractController<EntityImplA> { 
    public void DoSomethingImpl(EntityImplA entity) { ... } 
} 

演員陣容仍然存在,但現在它是所有實現共享。

+2

良好的解決方法。有點像從非泛型接口到泛型抽象類的適配器。 – Baldrick

0

這是仿製藥的最佳使用案例。爲此,請按照Baldrick的說法爲您的界面添加通用約束。

如果 - 不管是什麼奇怪的原因 - 你不想將改變界面,你被困在一個非常醜陋的解決方案,從您的API隱藏鑄造:

public class ControllerImplA : IController 
{ 
    public void doSomething(IEntity entity) 
    { 
     this.doSomething((EntityImplA) entity); 
    } 

    public void doSomething(EntityImplA entity) 
    { 
     ... 
    } 
} 

這樣你就可以同時使用方法,從接口重定向到另一個的方法,以及在你的類上定義的派生類,而不是在接口上定義的方法。

var myIEntity = ... 
var myEntity = new EntityImplA(); 
myControler.doSomething(myIEntity); // calls the interface-method 
myControler.doSomething(myEntity); // direclty calls the class-method 

你也可以明確地實現你的接口,這樣從接口接入方法時,你看到的只是更通用的方法,而在具體的類,你只能看到更具體的實施。