如何删除重复的 Ninject 绑定?

How to remove repetitive Ninject Bindings?

我当前的 GeneralBindings:Ninject 模块

public class GeneralBindings : NinjectModule
    {
        public override void Load()
        {
            // Requires Ninject.Extensions.Conventions
            // This binds all interfaces to concretes of the same name eg IClass -> Class.
            Kernel.Bind(x => x.FromAssembliesMatching("Company.Project.Scm*")
                .SelectAllClasses()
                .Excluding(typeof(AffectedCables),
                    typeof(ApplicationConfigurations),
                    typeof(ApplicationErrors),
                    typeof(ApplicationLogEvents),
                    typeof(AppUsers),
                    typeof(AppUsersContract),
                    typeof(Areas)

                    // etc..

                )
                .BindAllInterfaces());

然后

            Bind<IAffectedCables>().To<AffectedCables>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AffectedCables");

            Bind<IApplicationErrors>().To<ApplicationErrors>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppErrors");

            Bind<IApplicationConfigurations>().To<ApplicationConfigurations>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppConfigurations");

            Bind<IApplicationLogEvents>().To<ApplicationLogEvents>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppEventLogs");

            Bind<IAppUsers>().To<AppUsers>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppUsers");

            Bind<IAppUsersContract>().To<AppUsersContract>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/AppUserContract");

            Bind<IAreas>().To<Areas>()
                .InSingletonScope()
                .WithConstructorArgument("url", @"api/Areas");

            // Etc...
...

谁能建议如何做得更好?我确信有人可以创建一行代码来保存我现在必须执行的复制和粘贴操作。

盲目拍摄,未测试,但我会尝试使用属性

public class AutoBindWithRouteAttribute : Attribute
{
    public string Route { get; }

    public AutoBindWithRouteAttribute(string route = null)
    {
        Route = route;
    }
}

然后

    // to bind your first block of code for classes not featuring the attribute
    kernel.Bind(
        x => x.FromAssembliesMatching("").SelectAllClasses()
            .Where(t => !t.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).Any())
           .BindAllInterfaces());

    // to bind your second block of code for classes featuring the attribute
    kernel.Bind(
        x => x.FromAssembliesMatching("").SelectAllClasses()
            .Where(t => t.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).Any())
            .BindWith(new BindingGenerator()));

其中 BindingGenerator 是:

public class BindingGenerator : IBindingGenerator
{
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        var att =
            type.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).FirstOrDefault() as
                AutoBindWithRouteAttribute;
        if (att == null) yield break;

        yield return (IBindingWhenInNamedWithOrOnSyntax<object>)bindingRoot
            .Bind(type.GetInterfaces().First())
            .To(type)
            .InSingletonScope()
            .WithConstructorArgument("url", att.Route ?? $"api/{type.Name}");
    }
}

用法将是:

[AutoBindWithRoute()]
public class AffectedCables : IAffectedCables

[AutoBindWithRoute(@"api/AppErrors")]
public class ApplicationErrors : IApplicationErrors

根据 jbl 的优秀建议解决方案,因为我有

 public class AffectedCables : DataAccessBase<AffectedCableEntity>, IAffectedCables
    {
...
    }

BindingGenerator 绑定了 DataAccessBase 所以我做了一个小改动以改用相关接口:

public class BindingGenerator : IBindingGenerator
        {
            public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type,IBindingRoot bindingRoot)
            {
                var att =
                    type.GetCustomAttributes(typeof(AutoBindWithRouteAttribute), false).FirstOrDefault() as
                        AutoBindWithRouteAttribute;
                if (att == null) yield break;

                yield return (IBindingWhenInNamedWithOrOnSyntax<object>) bindingRoot
                    .Bind(type.GetInterfaces().First(x => x.Name == $"I{type.Name}"))
                    .To(type)
                    .InSingletonScope()
                    .WithConstructorArgument("url", att.Route ?? $@"api/{type.Name}");
            }
        }