Свободный дизайн API в C# с вложенными общими ограничениями

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

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

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,

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

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

0 ответов

Я попытался параметризовать оба параметра 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()); 
Другие вопросы по тегам