是否可以获取类类型的引用/指针并强制它从特定的基类派生?
我正在编写一个客户端库,需要与服务器协商以选择用于通信的算法。我希望库的用户能够选择要使用的算法子集,而不是固定到我最初提供的集合(即,在某种工厂类中没有修复)。
理想情况下,这可以通过传入派生自某些常见“算法”子类型的类列表来完成。我已经看过“Type”对象,但我必须自己检查所有类型。有没有办法让编译器为我做这个?我想要的是像“Type< Algorithm>”这样的东西但我找不到那样的东西。或者完全有不同的方法来做这件事吗?
到目前为止我所想到的一个例子:
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 :(得分:3)
是否有理由在调用Communicate()之前不想实例化Algorithm对象?
如果您愿意传递实例列表,那么您可以这样做:
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。
答案 1 :(得分:1)
通过这样做,您可以将IAlgorithm接口公开给潜在的集成开发人员,以实现他们所需的接口,并使其与您的服务器一起使用。 (这种设置的安全性和这是一个好主意或不是另一个讨论:)
答案 2 :(得分:1)
一种方法是让/要求库的用户传递算法实例而不是类型。您的可用算法列表只是一个List,编译器将强制执行类型要求。只使用提供的算法实例,您的库不负责构建算法实例。 (如果您的用户提供的实例是工厂而不是实际算法,这也会有效。)
另一种方法是使用MEF来允许库用户聚合他们想要使用的算法,而不需要直接参与。您将库设置为Algorithm的使用者,并使用MEF在运行时枚举算法的可用提供程序。库用户将他们的应用程序设置为包含N个实现算法的类,MEF将它们全部绘制在一起,并在顶部显示它们。
答案 3 :(得分:0)
public class Client<T> where T : Algorithm
{
...
}
您可以访问T,如果需要实际类型,可以使用typeof(T)。无需将任何内容传递给构造函数。但是,这只适用于一种算法,因此可能无法回答您的问题。 (您可以添加更多类型参数,但它将被修复,而不是像数组一样开放)
答案 4 :(得分: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(derivedFrom)会做同样的伎俩。
答案 5 :(得分:0)
您有两个选项可以使用接口来定义您想要的基本合同行为来代替您的任何类型,并为您的库定义的每种类型的连接或算法都实现此接口。
或者定义一个抽象基类型,然后使用泛型来约束传递给连接或algortihm选择器方法的类型争论。所以你可以在你的用户界面上有一个简单的组合框,允许你的用户选择他们想要使用的算法,以便一种方法满足你对这个非常上下文场景的所有需求,提出一个简单的方法来满足你的需求然后是'GENERIC-ISE'它...它永远不会流行lol。
public void algPicker(T t) where T: <base class name>
{
}
或者您可以使用界面。
public void algPicker(T t) where T: <interface name>
{
}
他们称之为将通用约束应用于类型争论。
或...忘记泛型。
public void algPicker(MyInterface type)
{
}
不是实现通用设置,只需使用接口并将您的方法与特定类型的特定类型分离,而不是与一组所有类型实现相同接口的类型分离。这样你就会知道只有一组类型可以传递给你的算法选择器方法,因为它们都需要实现相同的接口,以便它们成为上面定义的方法的有效参数。
为了理解上述解决方案,您需要阅读泛型,抽象和接口。
快乐的阅读和快乐的编码。
答案 6 :(得分: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>()
});