Можно ли создать универсальную фабрику с конструктором с параметрами, используя Activator.CreateInstance ()? - PullRequest
0 голосов
/ 25 января 2012

Есть ли способ достичь универсальной фабрики, когда класс, который она возвращает, требует параметра в конструкторе? Все мои заводы выглядят так:

public static class UserServiceFactory
{
    public static UserService GetService()
    {
        UserRepository userRepository = new UserRepository();
        return new UserService(userRepository);
    }

}

Я пробовал что-то вроде этого:

 public static TServiceClass GetService<TServiceClass>()
        where TServiceClass : class, new()
    {
        TServiceClass serviceClass = null;

        string repositoryName = typeof (TServiceClass).ToString().Replace("Service", "Repository");
        Type type = Type.GetType(repositoryName);

        if (type != null)
        {
            object repository = Activator.CreateInstance(type);
            serviceClass =  (TServiceClass)Activator.CreateInstance(typeof (TServiceClass), new[]{repository});
        }

        return serviceClass;
    }

Однако это, конечно, не сработает, потому что я не могу использовать класс, у которого нет конструктора без параметров, в качестве универсального параметра, но я чувствую, что я близок. Я думал о передаче класса Service, как GetService(Type serviceClassType), но тогда я не могу объявить тип возвращаемого значения метода, и мне придется приводить его при вызове, чего я хочу избежать.

Есть ли другой подход? Это вообще возможно?

1 Ответ

3 голосов
/ 25 января 2012

Вы можете сделать что-то подобное и принять оба типа в качестве параметров типа:

public static TService GetService<TRepository, TService>() where TRepository:new()
{
    var repository = new TRepository();
    return (TService)Activator.CreateInstance(typeof(TService), repository);
}

Или, если вы хотите полагаться на соглашение, что служба и хранилище имеют одно и то же имя (только для иллюстрации):

public static TService GetService<TService>()
{
    var repositoryName = String.Concat(typeof(TService).Namespace, Type.Delimiter, typeof(TService).Name.Replace("Service", "Repository"));
    object repository = Activator.CreateInstance(Type.GetType(repositoryName));
    return (TService)Activator.CreateInstance(typeof(TService), repository);
}

Это кажется неочевидным и неинтуитивным, и, возможно, существуют более эффективные и надежные решения.

Возможно, использование инверсии контейнера управления подойдеткак лучший подход.

Используя контейнер, я бы просто разрешил UserService и позволил бы контейнеру внедрить соответствующий репозиторий.Если UserService является зависимостью от чего-то другого, пусть это разрешит контейнер DI, а современный контейнер разрешит зависимости зависимостей.

...