2010-08-03 175 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

相关问题