有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java参数化系统。C中的类型变量#

我试图在C#中创建一个工厂类,它返回属于或扩展特定基类型的对象。每次在工厂中调用getInstance()时,我都需要实例化这个类型的新实例,所以我真的只想接受并存储类型本身。在Java中,我使用Class<? extends Base>来保存要创建的类,然后对其调用getInstance()

我知道如何使用C#中的Activator类从System.Type创建新对象,但我不确定的是类类型的约束。我希望只能接受属于或扩展基类的类型。我意识到我可以更改工厂上的setter,以接受基类型的实际对象,然后从中检索类型,但我并不想仅仅为了检索类型变量而实例化整个对象

下面是一个Java程序的小例子,只是为了演示我需要什么,以防我的问题不清楚。在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.");
   }
}

共 (2) 个答案

  1. # 1 楼答案

    我不知道如何在编译时强制执行此操作,但如果您对运行时检查没有意见,可以这样做:

    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);
        }
    }
    
  2. # 2 楼答案

    您可以使“GetInstance”方法成为动态的,这样在设置类时,也可以设置该方法。这样,您就可以在运行时依赖泛型来获得正确的类型。它可能是这样的:

    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();
        }
    }