簡體   English   中英

使用類型來實例化使用受限泛型的派生類

[英]Using a type to instantiate a derived class which uses restricted generics

我正在使用通用工廠類,其中通用部分是正在使用的派生類。 正常用法很明確: BaseClass<DerivedA> C = new BaseClass<DerivedA>(). 現在雖然我試圖將屬性注入到我使用這些類的類中。 為此,我嘗試將Type作為參數(以便我可以注入正在使用的派生類)。

現在雖然我有點不知所措,盡管我正在尋找自己的例子和自己。 而我現在想知道:這樣的構造是否可以使用? 如果是這樣,我如何實例化該類並使用Exists和ExistsB?

用法:

public class MyMainClass
{
    object _ClassInstance; // BaseClass<DerivedA> or BaseClass<DerivedB>

    public MyyMainClass(Type typeIWant)
    {
          .....
    }
}

....
MyMainClass a = new MyMainClass(typeof(DerivedA));
MyMainClass b = new MyMainClass(typeof(DerivedB));

通用類:

public abstract class BaseClass<T> where T: BaseClass<T>, new()
{
...
    public bool Exists(int a) {...}
}

派生類:

public class DerivedA :BaseClass<DerivedA>
{
...
}

public class DerivedB :BaseClass<DerivedB>
{
...
   public bool ExistsB(string a) {...}
}

您可以使用以下方法創建任何類型的實例:

_ClassInstance = Activator.CreateInstance(typeIWant)

但是不建議使用它,因為當您想要使用其中一種BaseClass方法時,您將永遠檢查其類型並進行轉換。 如果您能夠更改主類以獲取類型參數,它應如下所示:

public class MyMainClass<T> where T: BaseClass<T>, new()
{
    T _ClassInstance; // BaseClass<DerivedA> or BaseClass<DerivedB>

    public MyMainClass()
    {
        _ClassInstance = new T();
    }
}

這將允許您使用BaseClass上定義的任何方法。 如果你想使用ExistsB,那么你仍然需要在運行時檢查它的類型並進行轉換。 我會推薦這樣的東西:

if (_ClassInstance is DerivedB derivedB)
    derivedB.ExistsB("...");

如果你真的需要編譯時檢查,我會推薦它,你的類需要改變。 您不能僅使用對基類的引用來訪問派生類上定義的方法或屬性。

這是你想要的嗎?

Object instance1 = Activator.CreateInstance<Object>();
Object instance2 = Activator.CreateInstance(typeof(object));

我建議你使用getType來獲取一個類型名稱。 如果您升級繼承(從DerivedB等繼承另一個類),如果使用getType您可以確保僅為DerivedB類型的實例調用此方法。

MyMainClass b = new MyMainClass(typeof(DerivedB));

if(b.GetType() == typeof(DerivedB)) 
b.ExistsB(...);

這是抽象類的主要問題 - 您共享接口和實現。 但在您的情況下,您強烈依賴於不同的接口。 要簡化問題,只需看看你真正想要的東西:

public interface IExistable<in TValue>
{
    bool Exists(TValue value);
}

public interface IDerivedA : IExistable<int>
{
}

public interface IDerivedB : IExistable<int>, IExistable<string>
{
}

正如您所看到的,您使用兩個接口過度復雜IDerivedB,即,您的MainClass在某些情況下依賴於IDerivedB。 擴展接口也不錯,你只是錯誤地使用它。 所以你必須做的是為你的MainClass定義接口:

public interface IMainClass
{
    //some methods here
}

並創建兩個實現:

public class ConcreteMainClass : CommonMainClass //you can derive from common, delegate to inner instance or implement interface from scratch - you decide depending on situation
{
    private readonly IDerivedB _instance;
    public ConcreteMainClass(IDerivedB instance) : base(instance)
    {
        _instance = instance;
    }

    //you can override some logic here depending on IExistable<string> from IDerivedB
}

public class CommonMainClass : IMainClass
{
    private readonly IExistable<int> _instance;
    public CommonMainClass(IExistable<int> instance)
    {
        _instance = instance;
    }

    //this is where you don't depend on IExistable<string>
}

這樣你就可以編寫更清晰的代碼:

IMainClass a = new CommonMainClass(new DerivedA());
IMainClass b = new ConcreteMainClass(new DerivedB());

PS :最好將依賴關系傳遞給類生命周期的上層,而不是在內部激活它,這樣你就可以使用工廠為你創建它們甚至是依賴注入。

PS2 :在抽象類之前使用接口。 接口/構造函數/方法描述了您的整體依賴關系。 另一方面,抽象類只是重用實現的一種方式 - 它們不是用來定義接口或者你如何使用類,你可以使整個主體私有/受保護而不會分享任何東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM