简体   繁体   English

C#中的参数化System.Type变量

[英]Parameterized System.Type Variable in C#

I am trying to make a factory class in C# that returns objects that are or extend a certain base type. 我正在尝试在C#中创建一个工厂类,该工厂类返回的对象是或扩展了某种基本类型。 I need to instantiate a new instance of this type every time I call getInstance() on the factory, so I really only want to accept and store the type itself. 每当我在工厂调用getInstance() ,我都需要实例化此类型的新实例,因此我真的只想接受并存储该类型本身。 In Java I have used the Class<? extends Base> 在Java中,我使用了Class<? extends Base> Class<? extends Base> to hold the class to create and then called getInstance() on it. Class<? extends Base>来保存要创建的类,然后在其上调用getInstance()

I understand how to use the Activator class in C# to create new object from a System.Type but the part I'm not sure about is the constraint on the class type. 我了解如何在C#中使用Activator类从System.Type创建新对象,但是我不确定的部分是对类类型的约束。 I want to be able to only accept Types that are or extend the base class. 我希望只能接受属于或扩展基类的Type。 I realize that I could change the setter on the factory to accept an actual object of the base type then retrieve the type from it, but I didn't really want to instantiate an entire object just to retrieve a Type variable. 我意识到我可以在工厂中将设置器更改为接受基本类型的实际对象,然后从中检索类型,但是我并不是真的想实例化整个对象只是为了检索Type变量。

Below is a little example Java program just to demonstrate what I need, in case my question is not clear. 下面是一个小的Java程序示例,目的是演示我的需求,以防我的问题不清楚。 Is there any way to do this in C#? 在C#中有什么方法可以做到这一点?

class Program {
   public static void main(String[] args) throws InstantiationException, IllegalAccessException {
         Factory.setClass(Base.class);
         Base b = Factory.getInstance();
         b.Print();

         Factory.setClass(Child.class);
         b = Factory.getInstance();
         b.Print();
      }
}

class Factory {
   private static Class<? extends Base> type;

   // What I want to do in C#.
   public static void setClass(Class<? extends Base> newType) {
      type = newType;
   }

   // What I don't want to have to do in C#.
   public static void setClassFromObject(Base newTypeObject) {
      type = newTypeObject.getClass();
   }

   public static Base getInstance() throws InstantiationException, IllegalAccessException {
      return type.newInstance();
   }
}

class Base {
   public void Print() {
      System.out.println("Hello from base.");
   }
}

class Child extends Base {
   @Override
   public void Print() {
      System.out.println("Hello from child.");
   }
}

I don't see how to enforce this at compile time, but if you're OK with a runtime check, you could do it like this: 我看不到如何在编译时强制执行此操作,但是如果您可以通过运行时检查确定,则可以这样做:

class Factory 
{
    private static Type _type;

    public static void SetClass(Type t) 
    {
        if (!(typeof(Base)).IsAssignableFrom(t))
        {
            throw new ArgumentException("type does not extend Base", nameof(t));
        }

        _type = t;
    }

    public static Base GetInstance() 
    {
        return (Base)Activator.CreateInstance(_type);
    }
}

You could make the "GetInstance" method dynamic, so that when you set the class, you also set the method. 您可以使“ GetInstance”方法动态化,以便在设置类时也可以设置该方法。 That way you could rely on generics at runtime to get you the right type. 这样,您可以在运行时依赖泛型来获取正确的类型。 It could look like this: 它可能看起来像这样:

public class Factory
{
    private static Func<Base> _getInstance;

    //option if you want to pass in an instantiated value
    public static void SetClass<T>(T newType) where T : Base, new()
    {
        _getInstance = () => new T();
    }

    //option if you just want to give it a type
    public static void SetClass<T>() where T : Base, new()
    {
        _getInstance = () => new T();
    }

    public static Base GetInstance()
    {
        return _getInstance();
    }

    //you could just make GetInstance Generic as well, so you don't have to set the class first
    public static Base GetInstance<T>() where T : Base, new()
    {
        return new T();
    }
}

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

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