2010-08-03 178 views
1

是否有可能獲得引用/指向類類型的指針並強制它從特定的基類派生?如何在C#中引用特定的類類型?

我正在寫一個客戶端庫,需要與服務器協商選擇一種算法用於通信。我希望庫的用戶能夠選擇要使用的算法的子集,而不是固定到我最初提供的集合(即,不固定在某種工廠類中)。

理想情況下,這可以通過傳入從一些常見「算法」子類型派生的類的列表來完成。我看過「Type」對象,但我必須自己檢查所有類型。有沒有辦法讓編譯器爲我做這件事?我想要的是「類型<算法>」,但我找不到像這樣的東西。或者完全有不同的方式來做到這一點?

的是什麼,我認爲到目前爲止的例子:

public class Algorithm { 
    public static abstract Name; 
} 

public class Client { 
    public MyLib(Type[] algorithms) { 
     m_algorithms = algorithms; 
     // ... Check they all derive from Algorithm 
    } 

    public Communicate() { 
     // ... Send list of algorithm names to server 
     // ... Create instance of algorithm dictated by server response 
    } 
} 
+0

這也可以工作,或應該工作哈哈! (道格拉斯答案) 只需使用arraylist = List <>的繼承者,它應該允許您傳入一個類型化的列表對象,強類型爲您的基類或子類型,就像您將它放入As Algorithm一樣。我認爲它是抽象的,因爲它似乎沒有被實例化的理由,所以將其抽象並定義算法對象對應用程序或庫的意義的本質。 – IbrarMumtaz 2010-08-04 00:05:34

+0

將有很多狀態(未包含在本示例中)附加到算法。我需要實例化一個,並且不想實例化所有這些。對不起,如果這不明確在我的文章。 – 2010-08-04 08:48:38

回答

0

不幸的是你不能在編譯時檢查類型是否都是算法。這是我錯過Java(少數)功能之一。但是,有一些很好的解決方法,這取決於您的情況,可能比您希望的解決方案更好。例如:

public abstract class Algorithm { 
} 

public class AlgorithmA : Algorithm { } 
public class AlgorithmB : Algorithm { } 

public interface IAlgorithmFactory 
{ 
    string Name {get;} 
    Algorithm GetAlgorithm(); 
} 

public class AlgorithmFactory<T> : IAlgorithmFactory where T : Algorithm, new() 
{ 
    public string Name {get { return typeof(T).Name; }} 
    public Algorithm GetAlgorithm() 
    { 
     return new T(); 
    } 
} 

public class Client { 
    public void MyLib(IEnumerable<IAlgorithmFactory> algorithms) { 

    // ... Check they all derive from Algorithm 
    } 

    public void Communicate() { 
    // ... Send list of algorithm names to server 
    // ... Create instance of algorithm dictated by server response 
    } 
} 

然後你可以用你的客戶端類是這樣的:

new Client().MyLib(new IAlgorithmFactory[] 
        { 
         new AlgorithmFactory<AlgorithmA>(), 
         new AlgorithmFactory<AlgorithmB>() 
        }); 
+0

這看起來不錯。謝謝 – 2010-08-04 08:41:51

+0

我剛剛意識到,如果某個算法需要某種初始化狀態,那麼我可以爲它創建一個特定的工廠 - 只在需要時才使用鍋爐板,非常好。 – 2010-08-04 08:55:24

+0

準確地說。我跟着你的領導與'MyLib'的事情,因爲我不知道你到底在做什麼,但我會建議使用構造函數注入。這樣你可以用IoC框架做一些非常好的事情。 – StriplingWarrior 2010-08-04 16:14:48

0
public class Client<T> where T : Algorithm 
{ 
    ... 
} 

您可以訪問T,並且可以使用的typeof(T),如果你需要的實際類型。不需要傳遞任何東西到構造函數中。但是,這隻適用於一種算法,因此可能不會回答你的問題。 (你可以添加更多的類型參數,但它是固定的,不開放的結束就像一個數組)

1
  1. 創建一個接口,IAlgorithm,它定義了最小的方法定義的算法需要通過您的應用程序。
  2. 實施IAlgorithm接口至少一次。
  3. 限制自己只傳遞方法之間的IAlgorithm接口。

通過這樣做,您可以將IAlgorithm接口展示給潛在的集成開發人員,以實現您所需的接口並且仍然可以與您的服務器一起工作。 (這種設置的安全性以及這是個好主意或不是另一個討論)

0

Type對象具有屬性BaseType,該屬性是類從中直接派生的類型。您可以檢查類型的BaseType是否爲Algorithm類型,遞歸查找所有祖先類型。

bool IsDerivedFrom(Type typeToCheck, Type derivedFrom) 
    { 
     while (typeToCheck.BaseType != null) 
     { 
     if (typeToCheck.BaseType == derivedFrom) return true; 
     typeToCheck = typeToCheck.BaseType; 
     } 
     return false; 
    } 

注:如在評論中指出,使用typeToCheck.IsSubclassOf(衍生自)做了同樣的伎倆。

+0

或者只是調用Type.IsSubclassOf()。它走繼承鏈。 – dthorpe 2010-08-04 00:04:21

+0

我已經意識到這一點,但我希望編譯器會爲我做這件事 – 2010-08-04 08:38:10

3

是否有一個原因,你不想實例化算法對象,直到Communicate()被調用?

如果你很高興在實例列表通過,那麼你可以這樣做:

public class Client { 
    public MyLib(IList<Algorithm> algorithms) { 
     m_algorithms = algorithms; 
     // ... They all derive from Algorithm 
    } 
    public Communicate() { 
     // ... Send list of algorithm names to server 
     // ... Use instance of algorithm dictated by server response 
    } 
} 

這也將讓你寫算法的實現與優化參數,就像這樣:

public class MyAlgorithm : Algorithm { 
    public MyAlgorithm(int tolerance) { 
    // ... 
    } 
} 

Communicate將不必擔心如何構建MyAlgorithm。

+0

每個算法可能有很多的狀態,並需要耗時的初始化。 StriplingWarrior的答案看起來是最適合我想要做的。 – 2010-08-04 08:50:03

0

您有兩個選擇使用接口來定義您想要代替任何類型的基本合約行爲,並且爲您的庫定義的每種類型的連接或算法實現此接口。或者定義一個抽象基類型,然後使用泛型將約束類型的參數傳遞給連接或algortihm選擇器方法。所以你可以在你的UI上有一個簡單的組合框,它允許你的用戶選擇他們想要使用的alogrithm,爲了讓一種方法滿足這種非常情景化的場景的所有需求,想出一個簡單的方法來滿足您的需要然後'GENERIC-ISE'它...那永遠不會趕上哈哈。

public void algPicker(T t) where T: <base class name> 
{ 

} 

或者您可以使用接口。

public void algPicker(T t) where T: <interface name> 
{ 

} 

以上是他們所說的將泛型約束應用於類型的爭論。

或...忘了泛型。

public void algPicker(MyInterface type) 
{ 

} 

比實現一個通用的建立更確切地說,只是使用接口和特定於某一類型,但一組類型的所有這些實現相同的接口解耦方法。這樣你就會知道只有一組類型可以傳遞給你的算法選擇器方法,因爲它們都需要實現相同的接口,以便它們成爲上面定義的方法的有效參數。

爲了理解上述解決方案,您需要了解泛型,抽象和接口。

快樂閱讀和快樂編碼。

1

一種方法是讓/需要磁帶庫的用戶傳遞的算法,而不是類型的實例。您的可用算法列表就是一個List,編譯器將強制執行類型要求。您的庫不會負責構建算法實例,只需使用提供的算法實例即可。 (如果用戶提供的實例是工廠而不是實際算法,這也可以工作。)

另一種方法是使用MEF來允許庫用戶在沒有直接參與的情況下彙總他們想使用的算法所有。您將您的庫設置爲算法的使用者,並使用MEF在運行時枚舉算法的可用提供者。圖書館用戶將他們的應用程序設置爲包含N個實現算法的類,MEF將把它們全部繪製在一起,並將它們呈現在您的頭頂。

+0

將有一些狀態附加到算法,所以我不想創建那些不會被使用的。雖然MEF看起來很有趣,但我喜歡它基於用戶進口產品的想法。我將不得不更詳細地研究這一點。謝謝。 – 2010-08-04 08:46:21

相關問題