如何在责任链中注入下一个处理程序的依赖?

在我当前的项目中,我使用了很多责任链模式。


但是,我发现通过依赖注入来配置链有点尴尬。


给定这个模型:


public interface IChainOfResponsibility 

{

    IChainOfResponsibility Next { get; }

    void Handle(Foo foo);

}


public class HandlerOne : IChainOfResponsibility 

{

    private DbContext _dbContext;


    public HandlerOne(IChainOfResponsibility next, DbContext dbContext)

    {

        Next = next;

        _dbContext = dbContext;

    }


    public IChainOfResponsibility Next { get; }


    public void Handle(Foo foo) { /*...*/}

}


public class HandlerTwo : IChainOfResponsibility 

{

    private DbContext _dbContext;


    public HandlerTwo(IChainOfResponsibility next, DbContext dbContext)

    {

        Next = next;

        _dbContext = dbContext;

    }


    public IChainOfResponsibility Next { get; }


    public void Handle(Foo foo) { /*...*/}

}

我的启动变成:


public void ConfigureServices(IServiceCollection services)

{

    services.AddTransient<IChainOfResponsibility>(x => 

        new HandlerOne(x.GetRequiredService<HandlerTwo>(), x.GetRequiredService<DbContext>())

    );


    services.AddTransient(x => 

        new HandlerTwo(null, x.GetRequiredService<DbContext>())

    );

}

如何更干净地配置我的责任链?


浮云间
浏览 210回答 3
3回答

慕虎7371278

我破解了一个简单的解决方案,因为我找不到任何能满足我要求的东西。它工作正常,因为它用于IServiceProvider.GetRequiredService解决链中所有处理程序的所有构造函数依赖性。我的启动类变为:public void ConfigureServices(IServiceCollection services){&nbsp; &nbsp; services.Chain<IChainOfResponsibility>()&nbsp; &nbsp; &nbsp; &nbsp; .Add<HandlerOne>()&nbsp; &nbsp; &nbsp; &nbsp; .Add<HandlerTwo>()&nbsp; &nbsp; &nbsp; &nbsp; .Configure();}我正在做的是使用 Expression 动态生成问题中的 lambda。然后将其编译并注册到IServiceCollection.AddTransient.因为它生成编译代码,所以在运行时它应该与问题注册一样快。这是神奇的代码:public static class ChainConfigurator{&nbsp; &nbsp; public static IChainConfigurator<T> Chain<T>(this IServiceCollection services) where T : class&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return new ChainConfiguratorImpl<T>(services);&nbsp; &nbsp; }&nbsp; &nbsp; public interface IChainConfigurator<T>&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; IChainConfigurator<T> Add<TImplementation>() where TImplementation : T;&nbsp; &nbsp; &nbsp; &nbsp; void Configure();&nbsp; &nbsp; }&nbsp; &nbsp; private class ChainConfiguratorImpl<T> : IChainConfigurator<T> where T : class&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; private readonly IServiceCollection _services;&nbsp; &nbsp; &nbsp; &nbsp; private List<Type> _types;&nbsp; &nbsp; &nbsp; &nbsp; private Type _interfaceType;&nbsp; &nbsp; &nbsp; &nbsp; public ChainConfiguratorImpl(IServiceCollection services)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _services = services;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _types = new List<Type>();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _interfaceType = typeof(T);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public IChainConfigurator<T> Add<TImplementation>() where TImplementation : T&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var type = typeof(TImplementation);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _types.Add(type);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public void Configure()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_types.Count == 0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new InvalidOperationException($"No implementation defined for {_interfaceType.Name}");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foreach (var type in _types)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ConfigureType(type);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private void ConfigureType(Type currentType)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // gets the next type, as that will be injected in the current type&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nextType = _types.SkipWhile(x => x != currentType).SkipWhile(x => x == currentType).FirstOrDefault();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Makes a parameter expression, that is the IServiceProvider x&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var parameter = Expression.Parameter(typeof(IServiceProvider), "x");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // get constructor with highest number of parameters. Ideally, there should be only 1 constructor, but better be safe.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var ctor = currentType.GetConstructors().OrderByDescending(x => x.GetParameters().Count()).First();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // for each parameter in the constructor&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var ctorParameters = ctor.GetParameters().Select(p =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // check if it implements the interface. That's how we find which parameter to inject the next handler.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_interfaceType.IsAssignableFrom(p.ParameterType))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (nextType is null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // if there's no next type, current type is the last in the chain, so it just receives null&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Expression.Constant(null, _interfaceType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // if there is, then we call IServiceProvider.GetRequiredService to resolve next type for us&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Expression.Call(typeof(ServiceProviderServiceExtensions), "GetRequiredService", new Type[] { nextType }, parameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // this is a parameter we don't care about, so we just ask GetRequiredService to resolve it for us&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (Expression)Expression.Call(typeof(ServiceProviderServiceExtensions), "GetRequiredService", new Type[] { p.ParameterType }, parameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // cool, we have all of our constructors parameters set, so we build a "new" expression to invoke it.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var body = Expression.New(ctor, ctorParameters.ToArray());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // if current type is the first in our list, then we register it by the interface, otherwise by the concrete type&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var first = _types[0] == currentType;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var resolveType = first ? _interfaceType : currentType;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var expressionType = Expression.GetFuncType(typeof(IServiceProvider), resolveType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // finally, we can build our expression&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var expression = Expression.Lambda(expressionType, body, parameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // compile it&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var compiledExpression = (Func<IServiceProvider, object>)expression.Compile();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // and register it in the services collection as transient&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _services.AddTransient(resolveType, compiledExpression );&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}PS.:我正在回答我自己的问题以供将来参考(我自己和希望其他人),但我希望得到一些反馈。

侃侃尔雅

适用于最简单的依赖链情况的快速解决方案。&nbsp; &nbsp; public static IServiceCollection AddChained<TService>(this IServiceCollection services, params Type[] implementationTypes)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (implementationTypes.Length == 0)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentException("Pass at least one implementation type", nameof(implementationTypes));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; foreach(Type type in implementationTypes)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; services.AddScoped(type);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; int order = 0;&nbsp; &nbsp; &nbsp; &nbsp; services.AddTransient(typeof(TService), provider =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //starts again&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (order > implementationTypes.Length - 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; order = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Type type = implementationTypes[order];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; order++;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return provider.GetService(type);&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; return services;&nbsp; &nbsp; }接着services.AddChained<IService>(typeof(SomeTypeWithIService), typeof(SomeType));重要通知:需要非常小心地使用此解决方案,因为它在多线程场景中可能无法始终如一地工作。order变量在这里不是线程安全的。因此,它不能保证它总是会为我们的服务返回链中的第一个实现。例如,当我们调用时,services.GetService<IService>()我们希望SomeTypeWithIService始终收到实例,因为这是链中的第一个实现。但是如果我们在多个线程中执行相同的调用,我们有时会收到SomeType,因为order它不是线程安全的。

慕工程0101907

我通过引入 ChainLink(current, next) 的概念来发展你的想法。public class ItemDecoratorChainLink : IItemDecorator{&nbsp; &nbsp; private readonly IItemDecorator[] _decorators;&nbsp; &nbsp; public ItemDecoratorChainLink(&nbsp; &nbsp; &nbsp; &nbsp; IItemDecorator current,&nbsp; &nbsp; &nbsp; &nbsp; IItemDecorator next)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (current == null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentNullException(nameof(current));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; _decorators = next != null&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? new[] { current, next }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : new[] { current };&nbsp; &nbsp; }&nbsp; &nbsp; public bool CanHandle(Item item) =>&nbsp; &nbsp; &nbsp; &nbsp; _decorators.Any(d => d.CanHandle(item));&nbsp; &nbsp; public void Decorate(Item item)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var decorators = _decorators.Where(d => d.CanHandle(item)).ToArray();&nbsp; &nbsp; &nbsp; &nbsp; foreach (var decorator in decorators)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; decorator.Decorate(item);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}因此,您不需要在链接内保留对“下一个”链接的引用,但会增加 chainLink 的负担。你的链接,其中,变得更干净,从重复中解脱出来,并且可以关心单一的责任。以下是链构建器的代码:public class ComponentChainBuilder<TInterface> : IChainBuilder<TInterface>&nbsp; &nbsp; where TInterface : class{&nbsp; &nbsp; private static readonly Type InterfaceType = typeof(TInterface);&nbsp; &nbsp; private readonly List<Type> _chain = new List<Type>();&nbsp; &nbsp; private readonly IServiceCollection _container;&nbsp; &nbsp; private readonly ConstructorInfo _chainLinkCtor;&nbsp; &nbsp; private readonly string _currentImplementationArgName;&nbsp; &nbsp; private readonly string _nextImplementationArgName;&nbsp; &nbsp; public ComponentChainBuilder(&nbsp; &nbsp; &nbsp; &nbsp; IServiceCollection container,&nbsp; &nbsp; &nbsp; &nbsp; Type chainLinkType,&nbsp; &nbsp; &nbsp; &nbsp; string currentImplementationArgName,&nbsp; &nbsp; &nbsp; &nbsp; string nextImplementationArgName)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _container = container;//.GuardNotNull(nameof(container));&nbsp; &nbsp; &nbsp; &nbsp; _chainLinkCtor = chainLinkType.GetConstructors().First();//.GuardNotNull(nameof(chainLinkType));&nbsp; &nbsp; &nbsp; &nbsp; _currentImplementationArgName = currentImplementationArgName;//.GuardNeitherNullNorWhitespace(nameof(currentImplementationArgName));&nbsp; &nbsp; &nbsp; &nbsp; _nextImplementationArgName = nextImplementationArgName;//.GuardNeitherNullNorWhitespace(nameof(nextImplementationArgName));&nbsp; &nbsp; }&nbsp; &nbsp; /// <inheritdoc />&nbsp; &nbsp; public IChainBuilder<TInterface> Link(Type implementationType)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _chain.Add(implementationType);&nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; }&nbsp; &nbsp; /// <inheritdoc />&nbsp; &nbsp; public IChainBuilder<TInterface> Link<TImplementationType>()&nbsp; &nbsp; &nbsp; where TImplementationType : class, TInterface&nbsp; &nbsp; &nbsp; &nbsp; => Link(typeof(TImplementationType));&nbsp; &nbsp; public IServiceCollection Build(ServiceLifetime serviceLifetime = ServiceLifetime.Transient)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (_chain.Count == 0)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new InvalidOperationException("At least one link must be registered.");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var serviceProviderParameter = Expression.Parameter(typeof(IServiceProvider), "x");&nbsp; &nbsp; &nbsp; &nbsp; Expression chainLink = null;&nbsp; &nbsp; &nbsp; &nbsp; for (var i = _chain.Count - 1; i > 0; i--)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var currentLink = CreateLinkExpression(_chain[i - 1], serviceProviderParameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nextLink = chainLink ?? CreateLinkExpression(_chain[i], serviceProviderParameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chainLink = CreateChainLinkExpression(currentLink, nextLink, serviceProviderParameter);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (chainLink == null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // only one type is defined so we use it to register dependency&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _container.Add(new ServiceDescriptor(InterfaceType, _chain[0], serviceLifetime));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // chain is built so we use it to register dependency&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var expressionType = Expression.GetFuncType(typeof(IServiceProvider), InterfaceType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var createChainLinkLambda = Expression.Lambda(expressionType, chainLink, serviceProviderParameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var createChainLinkFunction = (Func<IServiceProvider, object>)createChainLinkLambda.Compile();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _container.Add(new ServiceDescriptor(InterfaceType, createChainLinkFunction, serviceLifetime));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return _container;&nbsp; &nbsp; }&nbsp; &nbsp; private NewExpression CreateLinkExpression(Type linkType, ParameterExpression serviceProviderParameter)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var linkCtor = linkType.GetConstructors().First();&nbsp; &nbsp; &nbsp; &nbsp; var linkCtorParameters = linkCtor.GetParameters()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Select(p => GetServiceProviderDependenciesExpression(p, serviceProviderParameter))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .ToArray();&nbsp; &nbsp; &nbsp; &nbsp; return Expression.New(linkCtor, linkCtorParameters);&nbsp; &nbsp; }&nbsp; &nbsp; private Expression CreateChainLinkExpression(&nbsp; &nbsp; &nbsp; &nbsp; Expression currentLink,&nbsp; &nbsp; &nbsp; &nbsp; Expression nextLink,&nbsp; &nbsp; &nbsp; &nbsp; ParameterExpression serviceProviderParameter)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var chainLinkCtorParameters = _chainLinkCtor.GetParameters().Select(p =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (p.Name == _currentImplementationArgName)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return currentLink;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (p.Name == _nextImplementationArgName)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nextLink;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return GetServiceProviderDependenciesExpression(p, serviceProviderParameter);&nbsp; &nbsp; &nbsp; &nbsp; }).ToArray();&nbsp; &nbsp; &nbsp; &nbsp; return Expression.New(_chainLinkCtor, chainLinkCtorParameters);&nbsp; &nbsp; }&nbsp; &nbsp; private static Expression GetServiceProviderDependenciesExpression(ParameterInfo parameter, ParameterExpression serviceProviderParameter)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // this is a parameter we don't care about, so we just ask GetRequiredService to resolve it for us&nbsp; &nbsp; &nbsp; &nbsp; return Expression.Call(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; typeof(ServiceProviderServiceExtensions),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nameof(ServiceProviderServiceExtensions.GetRequiredService),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new[] { parameter.ParameterType },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; serviceProviderParameter);&nbsp; &nbsp; }}及其扩展:&nbsp; &nbsp;public static IChainBuilder<TInterface> Chain<TInterface, TChainLink>(&nbsp; &nbsp; &nbsp; &nbsp; this IServiceCollection container,&nbsp; &nbsp; &nbsp; &nbsp; string currentImplementationArgumentName = "current",&nbsp; &nbsp; &nbsp; &nbsp; string nextImplementationArgumentName = "next")&nbsp; &nbsp; &nbsp; &nbsp; where TInterface : class&nbsp; &nbsp; &nbsp; &nbsp; where TChainLink : TInterface&nbsp; &nbsp; &nbsp; &nbsp; => new ComponentChainBuilder<TInterface>(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; container,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; typeof(TChainLink),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentImplementationArgumentName,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nextImplementationArgumentName);构建链的代码如下所示:&nbsp; &nbsp; &nbsp; &nbsp; serviceProvider.Chain<IItemDecorator, ItemDecoratorChainLink>()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Link<ChannelItemDecorator>()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Link<CompetitionItemDecorator>()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Link<ProgramItemDecorator>()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Build(ServiceLifetime.Singleton);这种方法的完整示例可以在我的 GitHub 上找到:https://github.com/alex-valchuk/dot-net-expressions/blob/master/NetExpressions/ConsoleApp1/ConsoleApp1/ChainBuilder/ComponentChainBuilder.cs
打开App,查看更多内容
随时随地看视频慕课网APP