Параметризованная переменная System.Type в C # - PullRequest
0 голосов
/ 19 декабря 2018

Я пытаюсь создать фабричный класс в C #, который возвращает объекты, которые являются или расширяют определенный базовый тип.Мне нужно создавать новый экземпляр этого типа каждый раз, когда я вызываю getInstance() на фабрике, поэтому я действительно хочу только принять и сохранить сам тип.В Java я использовал Class<? extends Base> для хранения класса для создания и затем вызывал getInstance() для него.

Я понимаю, как использовать класс Activator в C # для создания нового объекта из System.Type, ночасть, в которой я не уверен, это ограничение на тип класса.Я хочу иметь возможность принимать только те типы, которые являются базовым классом или расширяют его.Я понимаю, что мог бы изменить установщик на фабрике так, чтобы он принимал фактический объект базового типа, а затем извлекал тип из него, но на самом деле я не хотел создавать экземпляр всего объекта просто для получения переменной типа.

Ниже приведен небольшой пример 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 ]

0 голосов
/ 19 декабря 2018

Вы можете сделать метод 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();
    }
}
0 голосов
/ 19 декабря 2018

Я не вижу, как применить это во время компиляции, но если вы в порядке с проверкой во время выполнения, вы можете сделать это так:

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...