简体   繁体   English

如何在C#中引用特定的类类型?

[英]How do I reference a specific class type in C#?

Is it possible to obtain a reference/pointer to a class type and enforce that it derives from a particular base class? 是否有可能获得对类类型的引用/指针并强制其从特定的基类派生?

I'm writing a client library that needs to negotiate with a server to pick an algorithm to use for communication. 我正在编写一个客户端库,该客户端库需要与服务器协商以选择用于通信的算法。 I want the user of the library to be able to select a subset of algorithms to use and not be fixed to the set I initially provide (ie. not fixed in some kind of factory class). 我希望库的用户能够选择要使用的算法子集,而不要固定到最初提供的集合(即,不固定在某种工厂类中)。

Ideally this would be done by passing in a list of classes that derive from some common "Algorithm" subtype. 理想情况下,这可以通过传入从某些常见“算法”子类型派生的类的列表来完成。 I've seen the "Type" object but I would have to check all the types myself. 我看过“类型”对象,但是我必须自己检查所有类型。 Is there a way to have the compiler do this for me? 有没有办法让编译器为我执行此操作? What I want is something like "Type<Algorithm>" but I can't find anything like that. 我想要的是“ Type <Algorithm>”之类的东西,但找不到类似的东西。 Or is there different way entirely to do this? 还是完全有其他方法可以做到这一点?

An example of what I've thought of so far: 到目前为止,我想到的一个例子:

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
    }
}

Is there a reason that you don't want to instantiate the Algorithm objects until Communicate() gets called? 您是否有理由不想在调用Communicate()之前实例化Algorithm对象?

If you were happy to pass in a list of instances, then you could do this: 如果您乐意传递实例列表,则可以执行以下操作:

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
    }
}

This would also allow you to write Algorithm implementations with tuning parameters, like this: 这也将允许您编写带有调整参数的算法实现,如下所示:

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

and Communicate won't have to worry about how to construct the MyAlgorithm. 和Communicate不必担心如何构造MyAlgorithm。

  1. Create an interface, IAlgorithm, that defines the minimum method definitions an algorithm requires by your app. 创建一个接口IAlgorithm,该接口定义您的应用程序算法需要的最小方法定义。
  2. Implement the IAlgorithm interface at least once. 至少一次实现IAlgorithm接口。
  3. Restrict yourself to passing ONLY the IAlgorithm interface between your methods. 限制自己只能在方法之间传递IAlgorithm接口。

By doing this you can expose your IAlgorithm interface to potential integration developers to implement your interface for what they need and still have it work with your server. 通过这样做,您可以将IAlgorithm接口公开给潜在的集成开发人员,以根据他们的需要实现您的接口,并使该接口仍可与您的服务器一起使用。 (Security of such a setup and whither this is a good idea or not is another discussion : ) (这种设置的安全性以及是否是个好主意是另一个讨论:)

One approach would be to let / require the user of your library to pass instances of algorithms instead of types. 一种方法是让/要求您的库用户传递算法实例而不是类型。 Your list of available algorithms is then simply a List and the compiler will enforce the type requirement. 您的可用算法列表就是一个列表,编译器将强制执行类型要求。 Your library would not be responsible for constructing instances of algorithms, just using the provided algorithm instances. 您的库仅使用提供的算法实例将不负责构造算法实例。 (This would also work if the instances provided by your user were factories rather than the actual algorithms.) (如果您的用户提供的实例是工厂而不是实际算法,这也将起作用。)

Another approach would be to use MEF to allow the library user to aggregate the algorithms they want to use without your direct involvement at all. 另一种方法是使用MEF ,使库用户无需他们的直接参与即可汇总他们要使用的算法。 You set up your library as a consumer of Algorithm, and use MEF to enumerate the available providers of Algorithm at runtime. 您将库设置为Algorithm的使用者,并使用MEF在运行时枚举Algorithm的可用提供程序。 The library user sets up their app to include N number of classes implementing Algorithm, and MEF will draw them all together and present them to you with a bow on top. 库用户将其应用程序设置为包括N个实现算法的类,MEF会将它们全部组合在一起,并在顶部用弓箭向您展示。

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

You have access to T, and can use typeof(T) if you need the actual Type. 您有权访问T,并且如果需要实际的Type,则可以使用typeof(T)。 No need to pass anything into the constructor. 无需将任何东西传递给构造函数。 However, this will only work with one algorithm, so probably does not answer your question. 但是,这仅适用于一种算法,因此可能无法回答您的问题。 (You could add more type parameters, but it would be fixed and not open ended like an array) (您可以添加更多类型参数,但是它将是固定的,并且不会像数组那样开放式)

The Type object has a property BaseType, which is the type from which the class immediately derives. Type对象具有一个BaseType属性,该属性是该类立即派生自的类型。 You could check if the type's BaseType is of type Algorithm, recursively looking for all ancestor types. 您可以递归查找所有祖先类型,然后检查类型的BaseType是否为Algorithm类型。

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

NOTE: As pointed out in a comment, use typeToCheck.IsSubclassOf(derivedFrom) does the same trick. 注意:如注释中指出,使用typeToCheck.IsSubclassOf(derivedFrom)可以达到相同的效果。

You've got two options use Interfaces to define the basic contractual behaviour that you want in place of any your types and have each type of connection or algorithm that you define for your library implement this Interface. 您有两个选项可以使用Interfaces定义所需的基本契约行为,以代替任何类型,并为您的库定义的每种连接或算法类型都实现此Interface。

Or define an abstract base type and then use generics to constraint type arguements passed into a connection or algortihm chooser method. 或定义一个抽象的基本类型,然后使用泛型来约束传递给连接或算法选择器方法的类型争论。 So you could have a simple combo box on your UI, that allows your user to select the alogrithm that they want to use, in order for one method to service all your needs for this very contextual scenario, come up with a simple method that meets your needs then 'GENERIC-ISE' it ... thats never gonna catch on lol. 因此,您可以在UI上有一个简单的组合框,该框允许您的用户选择他们要使用的算法,以便一种方法可以满足您在这种情况下的所有需要​​,并提出一种简单的方法来满足您的需求然后“ GENERIC-ISE”就可以了……那绝对不会流行。

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

}

or you could use an interface. 或者您可以使用界面。

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

}

Above is what they call applying generic constraints to type arguements. 以上是他们所谓的将一般约束应用于类型争论的内容。

or ... forget generics. 或...忘记泛型。

public void algPicker(MyInterface type)
{

}

Rather than implementing a generic set-up, just use interfaces and decouple your method from being specific to certain type but to a group of types all of which implement the same interface. 无需实现通用的设置,只需使用接口并将您的方法从特定于某种类型的特定类型中分离出来,而是分离到一组都实现相同接口的类型中。 This way you will know only a certain group of types can be passed into your algorithm picker method as they all need to implement the same Interface inorder for them to be valid parameters for the method defined above. 这样,您将知道只能将某些类型的类型传递到算法选择器方法中,因为它们都需要实现相同的接口,才能使它们成为上述方法的有效参数。

In order to understand the above solutions, you will need to have read up on generics, abstraction and interfaces. 为了理解上述解决方案,您将需要阅读泛型,抽象和接口。

Happy reading and happy coding. 愉快的阅读和愉快的编码。

You unfortunately can't check that the types are all Algorithms at compile time. 不幸的是,您在编译时无法检查类型是否全部为算法。 This is one of the (few) features I miss about Java. 这是我缺少的有关Java的(少数)功能之一。 However, there are some good workarounds, which (depending on your situation) may be better than the solution you were hoping for. 但是,有一些很好的解决方法,(取决于您的情况)可能比您希望的解决方案更好。 For example: 例如:

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
    }
}

Then you can use your client class like this: 然后,您可以像这样使用客户端类:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM