2015-10-27 66 views
2

也許這是一個愚蠢的問題。但是,我不明白我缺少的重點。抽象方法被混凝土類型覆蓋

考慮下面的類定義

public abstract class AbstractBaseClass 
{ 
    public abstract void Create(AnotherAbstractClass param1); 
} 

Wheras AnotherAbstractClass定義

public abstract class AnotherAbstractClass 
{ 
} 

一個具體實施

public class AnotherConcreteImplementation : AnotherAbstractClass 
{ 
} 

我希望能夠擁有的倍率Create使用具體類型的方法:

public class ConcreteImplementation : AbstractBaseClass 
{ 
    public override void Create(AnotherConcreteImplementation param1) <-- There is no suitable method for override 
    { 
     // param1 is an instance of the concrete implementation 
    } 

    public override void Create(AnotherAbstractClass param1) <-- this is working but I'll have to cast on each implementation 
    { 
     // param1 is an instance of the abstract class and needs a cast 
    } 
} 

這是根本不可能或有某種方式我不知道?也許使用泛型?

編輯#1(增加了更多的上下文)

我試圖實現/執行,在具體實現中只有一個參數有效。 認爲它是數據庫層。 Create方法將在數據庫中創建一個新條目。由於每個表具有不同的值,因此創建參數也具有。 可以通過AnotherAbstractClass的任何具體實現調用裏面的氣味(在我看來)。

public class AddressTable : AbstractBaseClass 
{ 
    public override void Create(AnotherAbstractClass param1) 
    { 
     // cast to concrete instance 
     var casted = (ConcreteAddressCreate)param1; 
    } 
} 

public class CityTable : AbstractBaseClass 
{ 
    public override void Create(AnotherAbstractClass param1) 
    { 
     // cast to concrete instance 
     var casted = (ConcreteCityCreate)param1; 
    } 
} 

具有AddressTable一個實例,我可以從另一方面調用

addressIntance.Create(new ConcreteAddressCreate()); // would be okay 

我可以把它

addressIntance.Create(new ConcreteCityCreate()); // would be okay but will fail at runtime with InvalidCastException 

編輯#2(附加信息)

應該也可以擴展AbstractBaseClass稍後使用更多抽象方法的類。 因此,對於我來說,更有可能使用泛型方法而不是具體的類實現,每種方法要實現200個泛型參數。

+1

大家笑回答您一般的代碼片段,沒有任何想法或真實意圖幫你,只是放棄一些點。基本上你問的是可能的,但它是一個巨大的代碼氣味,真正的問題是你爲什麼認爲你需要這個?你能否給我們更多的背景知識,因爲我相信有更好的課堂設計來達到你真正需要的。 – dustinmoris

+0

@dustinmoris我不回答,只是廢了一些觀點,我有很多這樣的東西,沒有用。我只是想向OP展示一個快速使用泛型來解決這個特定問題。我確實認爲這看起來像代碼味道。 – CodeCaster

+1

@dustinmoris這看起來不像是一種代碼味道,也沒有人會「爲點取捨」(無論如何,我總是很容易得到點數,但是我很難從中得到答案)。 –

回答

2

它違反了Liskov替代原則,所以它是非常有意義的,你不能這樣做。也就是說,你不能只是「有」協方差這樣的免費:

AbstractBaseClass bcl = new ConcreteImplementation(); 
bcl.Create(new DifferentImplementationWithoutSecondAbstract()); 

合同AbstractBaseClass定義使得Create工作的任何實施AbstractBaseClass中傳遞 - 如果你給什麼能約束被傳入你違反了它定義的合同。

就像你假定 - 你可以使用泛型:

// notice the recursive definition, we require the generic parameter 
// to be a generic parameter of itself - allowing AbstractBaseClass 
// to not be aware of its subclasses like in the other answers. 
public abstract class AbstractBaseClass<T> where T : AbstractBaseClass<T> 
{ 
    public abstract void Create(T param1); 
} 

public class Concrete : AbstractBaseClass<Concrete> 
{ 
    public override void Create(Concrete param1) 
    { 
     Console.WriteLine("Hello!"); 
    } 
} 
+1

這不是他要求的。你的例子中只有1個抽象類,但原始問題有2個抽象類。 – dustinmoris

+0

@dustinmoris我可以添加'公共抽象類SecondAbstractClass 其中T:SecondAbstractClass {public abstract void Create(T param1); }'然後讓'Concrete'擴展它。這不會增加答案的實質 - 因爲第二個抽象類,OP的問題不是真正引起的。這是因爲執行者對'AbstractBaseClass'部隊中的契約的約束造成的。 –

+0

T應該來自'AnotherAbstractClass',而不是'AbstractBaseClass'。這並不違反Liskov替代原則。 –

2

是的,你可以做到這一點使用泛型:

public abstract class AbstractBaseClass<T> 
    where T : AnotherAbstractClass 
{ 
    public abstract void Create(T param1); 
} 

public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation> 
{ 
    public override void Create(AnotherConcreteImplementation param1) 
    { 
    } 
} 
+1

這會強制'AbstractBaseClass'循環地意識到它的子類。 –

+1

爲什麼通用類。你可以使'Create'成爲一個通用的。所以這個'公共抽象無效創建(T參數1)其中,T:AnotherAbstractClass;'和重寫這樣的'公共覆蓋無效創建(T參數1){ }' –

+3

@ M.kazemAkhgary - 他們是不一樣的事情,使方法通用需要你處理和'AnotherAbstractClass'的子類,把它放在類上需要你只處理一個。 – Lee

0

泛型確實是這樣做的方式。

public abstract class AbstractBaseClass<TDerivedClass> where TDerivedClass : AnotherAbstractClass 
{ 
    public abstract void Create(TDerivedClass param1); 
} 

然後你就可以這樣做:

public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation> 
{ 
    public override void Create(AnotherConcreteImplementation param1) // Works because TDerivedClass = AnotherConcreteImplementation 
    { 
     ... 
    } 
} 
+0

這就像CodeCaster前一段的答案 - 從要求班級意識到其子類的相同問題 - 這不是必要的要求 - 請參閱我的答案以瞭解如何防止它。 –

+1

@BenjaminGruenbaum你能詳細說明一下這個類如何知道它的子類?看起來類需要注意* another *類型的子類 – dustinmoris

+0

它需要了解'AnotherAbstractClass' –