Ninject中基于类型约束的条件泛型绑定

时间:2016-10-28 17:12:37

标签: c# .net dependency-injection ninject

我需要在binding上执行通用Ninject,但我遇到了一些问题。这些是类:

public class BaseBL<TEntity> : IDisposable, IBaseBL<TEntity> 
        where TEntity : class
{
     ....
}
public class BaseLogAuditoriaBL<TEntity> : BaseBL<TEntity>, IBaseBL<TEntity> 
    where TEntity : BaseLogAuditoriaEntity
{
  ....
}

我希望当我的TEntity继承BaseLogAuditoriaEntity后,它会调用BaseLogAuditoriaBL,否则会调用BaseBL

在这种情况下,我如何以通用的方式配置我的bindings

如果我把它放在每个班级,它都有用,但是我需要一个针对这个问题的通用解决方案。

示例:

kernel.Bind(typeof(IBaseBL<>)).To(typeof(BaseBL<>));
kernel.Bind(typeof(IBaseBL<Loja>)).To(typeof(BaseLogAuditoriaBL<>));

1 个答案:

答案 0 :(得分:1)

您可以使用When(..)语法创建满足您需求的条件绑定:

public static class BaseBLBindingExtensions
{
    public static IBindingInNamedWithOrOnSyntax<object> WhenEntityMatchesType<TEntityType>(
        this IBindingWhenSyntax<object> syntax)
    {
        return syntax.When(request => DoesEntityMatchType(request, typeof(TEntityType)));
    }

    private static bool DoesEntityMatchType(IRequest request, Type typeToMatch)
    {
        return typeToMatch.IsAssignableFrom(request.Service.GenericTypeArguments.Single());
    }
}

然后使用它:

kernel.Bind(typeof(IBaseBL<>)).To(typeof(BaseBL<>));
kernel.Bind(typeof(IBaseBL<>)).To(typeof(BaseLogAuditoriaBL<>))
    .WhenEntityMatchesType<BaseLogAuditoriaEntity>();

完整示例包括单元测试(使用XUnit和FluentAssertions):

using FluentAssertions;
using Ninject;
using Ninject.Activation;
using Ninject.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace NinjectTest.SO40310046
{
    public interface IBaseBL<TEntity>
        where TEntity : class
    { }

    public class BaseBL<TEntity> : IBaseBL<TEntity>
        where TEntity : class
    { }

    public class SimpleEntity { }

    public class BaseLogAuditoriaEntity
    { }

    public class ChildBaseLogAuditorialEntity: BaseLogAuditoriaEntity
    { }

    public class BaseLogAuditoriaBL<TEntity> : BaseBL<TEntity>, IBaseBL<TEntity>
        where TEntity: BaseLogAuditoriaEntity
    { }

    public static class BaseBLBindingExtensions
    {
        public static IBindingInNamedWithOrOnSyntax<object> WhenEntityMatchesType<TEntityType>(this IBindingWhenSyntax<object> syntax)
        {
            return syntax.When(request => DoesEntityMatchType(request, typeof(TEntityType)));
        }

        private static bool DoesEntityMatchType(IRequest request, Type typeToMatch)
        {
            return typeToMatch.IsAssignableFrom(request.Service.GenericTypeArguments.Single());
        }
    }

    public class UnitTest
    {
        [Fact]
        public void Test()
        {
            var kernel = new StandardKernel();

            kernel.Bind(typeof(IBaseBL<>)).To(typeof(BaseBL<>));
            kernel.Bind(typeof(IBaseBL<>)).To(typeof(BaseLogAuditoriaBL<>))
                .WhenEntityMatchesType<BaseLogAuditoriaEntity>();


            kernel.Get<IBaseBL<SimpleEntity>>()
                .Should().BeOfType<BaseBL<SimpleEntity>>();

            kernel.Get<IBaseBL<BaseLogAuditoriaEntity>>()
                .Should().BeOfType<BaseLogAuditoriaBL<BaseLogAuditoriaEntity>>();

            kernel.Get<IBaseBL<ChildBaseLogAuditorialEntity>>()
                .Should().BeOfType<BaseLogAuditoriaBL<ChildBaseLogAuditorialEntity>>();
        }
    }
}

替代

考虑到您的BaseLogAuditoriaBL已经定义了类型约束,它可能是使用基于约定的绑定的可行替代方法(例如使用Ninject.Extensions.Conventions创建,它会扫描从BaseBL继承的类型,检查类型约束,然后扫描遵守约束的所有类型,然后为这些绑定创建特定的,非条件的绑定。 生成的绑定应该类似于:

kernel.Bind(typeof(IBaseBL<>)).To(typeof(BaseBL<>));
kernel.Bind(typeof(IBaseBL<BaseLogAuditoriaEntity>))
    .To(typeof(BaseLogAuditoriaBL<BaseLogAuditoriaEntity>));
kernel.Bind(typeof(IBaseBL<ChildBaseLogAuditoriaEntity>))
    .To(typeof(BaseLogAuditoriaBL<ChildBaseLogAuditoriaEntity>));

临:

  • 分辨率比使用When(...)约束
  • 时更快

缺点:

  • 仅在启动时知道包含实体的程序集时 - 适用约定时
  • 增加启动时间