Свободный дизайн API в C # с вложенными общими ограничениями - PullRequest
0 голосов
/ 22 октября 2018

В настоящее время я реализую API настройки IoC для внутреннего использования (в значительной степени вдохновленный модульной системой Autofac).

У нас есть Module s, которые настраиваются через строго типизированную конфигурацию, иЯ хочу, чтобы модуль мог требовать других модулей, поэтому у меня может быть основной модуль, похожий на «составной корень», который будет загружать все приложение целиком.

public interface IModule<TConfig>
{
    TConfig Config { get; }

    void Load(ContainerBuilder builder);

    void LoadExtraModules(ModuleRegister register);
}

Я сейчас занимаюсь проектированиемModuleRegister класс.То, что я хочу сделать, похоже на это:

public class MyModule : ModuleBase<ApplicationConfiguration>
{
    public void LoadExtraModules(ModuleRegister register)
    {
        register.Module<SqlModule>().WithConfig(new SqlConfiguration() { ... });
    }
}

public class SqlModule : ModuleBase<SqlConfiguration>
{
    public void Load(ContainerBuilder builder)
    {
         // configuration code.
    }
}

Мне бы хотелось, чтобы Intellisense как-то подсказал, что SqlConfiguration - это правильный тип конфигурации для SqlModule, но яне могу этого сделать: я хотел бы выразить параметр типа, похожий на

// ... inside an helper ExtraModulesRegister<TModule> class

public void WithConfig<TConfig>(TConfig configuration)
    where TModule : IModule<TConfig>
{
    ...
}

, но, очевидно, я могу выражать ограничения только для TConfig, а не для TModule.

Единственное решение, которое я нашел, этоиспользовать метод расширения, подобный следующему:

    public static void WithConfig<TConfig, TModule>(this ExtraModulesRegister<TModule> register,
        TConfig configuration)
        where TModule : IModule<TConfig>, new()
    {
        register.LoadModule<TModule, TConfig>(configuration);
    }

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

Я могу (почти)свободно менять дизайн всего.

Любое предложение приветствуется.

1 Ответ

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

Я попытался параметризовать оба параметра самим классом ExtraModulesRegister:

public class ExtraModulesRegister<TModule, TConfig> wher TModule : IModule<TConfig> {

    void WithConfig(TConfig config) {

    }

}

Но теперь вам может понадобиться какой-то трюк, чтобы TConfig был выведен из SqlConfig, поэтому вам не нужнопередать оба параметра.Я думаю, что-то вроде вспомогательного типа может помочь, поэтому вы вызываете register.Module(X<SqlModule>()), поэтому, передавая параметр чего-то вроде X<TModule> делает метод Module() выводит оба, TModule и TConfig.

public ExtraModulesRegister<TModule, TConfig> Module<TModule, TConfig>(X<TModule> module) where TModule : IModule<TConfig> {
    ...
}

class X<T> {}

public static X<T> X<T>() {
    return new X<T>();
}

К сожалению, похоже, что C # не может выводить типы.В Java работает один и тот же шаблон, и компилятор может вывести оба типа из одного аргумента и определенного отношения между ними.

Редактировать: Это работает в C #, но, возможно, это не синтаксис, вам бы хотелось:

public class ExtraModulesRegister<TConfig> {
    void WithConfig(TConfig config) {}
}

// Module method
public ExtraModulesRegister<TConfig> Module<TConfig>(IModule<TConfig> fakeModule) {
    Return new ExtraModulesRegister<TConfig>();
}

// Usage
register.Module(default(SqlModule)).WithConfig(new SqlConfig()); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...