2016-11-23 116 views
4

我有接口和3個派生它的類,但是如何爲每個類型使用1個變量?創建接口子類的實例

public interface IBuilder<T> where T: System.IConvertible{} 

    public class SimpleBuilder : IBuilder<SimpleCollagePatterns>{} 

    public class CreativeBuilder : IBuilder<CreativeCollagePatterns>{} 

    public class ShapeBuilder : IBuilder<ShapeCollagePatterns>{} 

我需要創建類的實例時,它單曲必要

我有IBuilder<IConvertible> currentBuilder變量,但只有當我改變IBuilder<IConvertible> currentBuilderIBuilder<SimpleCollagePatterns> currentBuilder我不能創建的任何Builder

this.currentBuilder = new SimpleBuilder(); //Doesn`t work 

實例或其他類型我可以創建這種類型的生成器,但我需要有可能創建任意類型

+0

接口不是類,所以你不能創建它們的實例。創建實例的唯一方法就是您選擇的方式,即定義實現該接口的類,例如SimpleCollagePatterns。另外接口不包含任何特定的代碼,所以你爲什麼要創建它們的實例呢?爲什麼不將IBuilder改爲父類? – jambonick

+0

你面臨的問題是你有'I '和'I '(即兩個不同的泛型參數使用相同的泛型接口),並且'T1'和'T2'之間有一個繼承層次結構。問題是'I '和'I '之間沒有繼承層次結構。您可以使用協變和逆變來處理這取決於繼承的方式,但是這會對類型的使用產生非常特定的限制,可能不是您想要的。總之,這是不可能做到的。 –

回答

0

我面臨同樣的情況。但最終發現沒有解決方案。在運行時無法創建任何類型的對象。正如你所說,將IBuilder currentBuilder改爲IBuilder currentBuilder是爲SimpleBuilder類型創建對象的唯一方法。其他情況也是如此。

+0

我有更多的方式使用'dynamic'類型的currentBuilder,但它不好 – SmiLe

+0

是的。這不好。所以解決方案是爲每種類型都有一個單獨的對象。 –

0

如果你真的想用一個變量所有場景,你可以隨時將其定義爲一個簡單的對象來保存到該實例,並使用is運算符來了解哪種它確實是在必要的時候是這樣的:

如果(this.currentBuilder是SimpleBuilder) {}

+0

但我不能改變它。我需要更改類型 – SmiLe

+0

爲什麼不能更改currentBuilder的聲明?這不是你自己的代碼嗎?因此,將IBuilder currentBuilder替換爲對象currentBuilder。 –

+0

如何做到這一點? – SmiLe

0

你想了解什麼叫協方差,這是由關鍵詞out表示在接口聲明中的泛型類型參數旁邊。

public interface IBuilder<out T> where T: System.IConvertible{} 

這將允許你聲明一個類型爲IBuilder<IConvertible>的變量並賦值,例如。 SimpleBuilder對它來說,你只需要知道應用協方差有什麼後果,最重要的是,普通的類型只能用作類型成員的返回類型。

如果您無法更改IBuilder接口 - 則無法爲所有情況創建變量。

欲瞭解更多信息,你可以研究SO,例如。 Difference between Covariance & Contra-variance或在源處閱讀,例如。 https://msdn.microsoft.com/en-us/library/mt654055.aspx

0

如果您若SimpleCollagePatterns由實現了特定的接口(在這種情況下ShapeBuilder),那麼你並不需要協方差類exclusivly使用不需要泛型類型

在特定的公共訪問

有一個簡單的設計模式,依靠單獨的繼承。

例如:

public interface IBuilder { 
    void Build(); 
} 

public interface IBuilder<T> : IBuilder { 
    T BuildParameter {get;} 
} 

注:BuildParameter對應於您BuildCollagePattern

然後你就可以實現該接口,因爲這樣:

public class SpecificBuilder : IBuilder<Int32> { 
    // The specific constructor 
    public SpecificBuilder(int param) { BuildParameter = param; } 

    // Implement from IBuilder 
    public void Build() { 
     System.Console.WriteLine("Building with Int32: " + BuildParameter); 
    } 

    // Implement from IBuilder<T> 
    public Int32 BuildParameter {get; private set;} 
} 

然後,你可以通過任何IBuilder<T>圍繞IBuilder

public class Program { 
    public static void Main() { 
     SpecificBuilder builder = new SpecificBuilder(42); 

     // SpecificBuilder implements IBuilder<Int32> 
     // Build accepts any IBuilder 
     // So this is legal: 
     Build(builder); 
    } 

    // 
    // Note this method accepts anything that inherits from IBuilder 
    // 
    public static void Build(IBuilder builder) { 

     builder.Build(); 

     // If you'd need access to the BuildParameter of IBuilder<T> 
     // then this pattern fails you here. 
     // Unless of course you want to check for types and cast 
    } 
} 

如前所述:一旦您需要訪問泛型類之外的類實現IBuilder<T>您需要開始區分類型並相應地投它們。不那麼優雅。

但你可以這樣設計很多東西並保持可擴展性。我提出這個問題,因爲我已經使用這種模式來實現自己的圖像過濾器,並且使用這種設計模式可能會非常容易實現這個過濾器。