0

我遇到过几篇文章,其中一个接口由多个类实现,并且依赖项已注册和解析。一篇这样的帖子就是这个

但是如何解决多个、多层次的依赖关系呢?

例如:

public enum ShortEnum { Short, Long }

public interface ISomeValidator
{
    bool ValidateInputString(string str);
}

public class ConValidator : ISomeValidator
{
    public bool ValidateInputString(string str) => true;
}

public class DonValidator : ISomeValidator
{
    public bool ValidateInputString(string str) => false;
}

public class ConProvider : ISomeProvider 
{
    ISomeValidator conValidator; // Expects instance of ConValidator
    public ConProvider(ISomeValidator someValidator)
    {
        conValidator = someValidator;
    }
}

public class DonProvider : ISomeProvider 
{
    ISomeValidator donValidator; // Expects instance of DonValidator
    public DonProvider(ISomeValidator someValidator)
    {
        donValidator = someValidator;
    }
}

ShortEnum可以用作键。这意味着根据它的值,返回ConProviderDonProvider返回。现在,提供者对 有依赖关系ISomeValidator,这又取决于 的键值ShortEnum可以解析为ConValidatoror的实例DonValidator

换句话说,我想构建以下两个对象图:

var provider1 = new ConProvider(new ConValidator());
var provider2 = new DonProvider(new DonValidator());

使用 .NET Core 3.1 内置依赖注入机制的最佳方式是什么?

4

2 回答 2

0

如果我理解正确,您希望ConValidatorinstance forConProviderDonValidatorinstance forDonProvider和 Providers 应该根据ShortEnum价值来解决。

我们可以像下面这样修改依赖项

public interface ISomeProvider
    {
        void Method1();
    }

    public interface ISomeValidator
    {
        bool ValidateInputString(string str);

    }

    public class ConValidator : ISomeValidator
    {
        public bool ValidateInputString(string str)
        {
            return true;
        }
    }

    public class DonValidator : ISomeValidator
    {
        public bool ValidateInputString(string str)
        {
            return false;
        }
    }

    public class ConProvider : ISomeProvider
    {
        ISomeValidator conValidator; // Expects instance of 
                                     //ConValidator
        public ConProvider(ValidatorResolver validatorResolver)
        {
            conValidator = validatorResolver(ShortEnum.Short);
        }

        public void Method1() {
            System.Console.WriteLine("Method1 COnProvider");
        }
    }

    public class DonProvider : ISomeProvider
    {
        ISomeValidator donValidator; // Expects instance of 
                                     //DonValidator
        public DonProvider(ValidatorResolver validatorResolver)
        {
            donValidator = validatorResolver(ShortEnum.Long);
        }

        public void Method1() {
            System.Console.WriteLine("Method1 DonProvider");
        }
    }

    public enum ShortEnum
    {
        Short,
        Long
    }

声明委托

public delegate ISomeProvider ProviderResolver(ShortEnum shortEnum);
public delegate ISomeValidator ValidatorResolver(ShortEnum shortEnum);

消费者服务

 public class SomeOtherService
    {
        private readonly ISomeProvider _provider;
        public SomeOtherService(ProviderResolver providerResolver)
        {
            _provider = providerResolver(ShortEnum.Short);
            //OR
            _provider = providerResolver(ShortEnum.Long);
            _provider.Method1();
        }
    }

在类ConfigureServices的方法StartUp

services.AddTransient<ConValidator>();
            services.AddTransient<DonValidator>();
            services.AddTransient<ConProvider>();
            services.AddTransient<DonProvider>();

            services.AddTransient<ProviderResolver>(serviceProvider => (shortEnum) =>
            {
                switch (shortEnum)
                {
                    case ShortEnum.Short:
                        return serviceProvider.GetService<ConProvider>();
                    case ShortEnum.Long:
                        return serviceProvider.GetService<DonProvider>();
                    default:
                        throw new KeyNotFoundException();
                }
            });

            services.AddTransient<ValidatorResolver>(serviceProvider => (shortEnum) =>
            {
                switch(shortEnum)
                {
                    case ShortEnum.Short:
                        return  serviceProvider.GetService<ConValidator>();
                    case ShortEnum.Long:
                        return serviceProvider.GetService<DonValidator>();
                    default:
                        throw new KeyNotFoundException();
                }
            });

            services.AddTransient<SomeOtherService>();
于 2022-02-19T12:22:18.510 回答
0

有三种方法可以实现您想要的。

第一种选择是通过注册一个完全组成所需对象图的委托来手动连接对象图,例如:

services.AddTransient<ISomeProvider>(
    c => new ConProvider(new ConValidator());
services.AddTransient<ISomeProvider>(
    c => new DonProvider(new DonValidator());

但是,一旦这些类获得其他依赖项,这将变得非常麻烦,因为您将很快开始完全绕过 DI 容器。

因此,作为第二种选择,您可以配置容器,只需要new两个提供者:

// Note how these validators are -not- registered by their interface!
services.AddTransient<ConValidator>(); // Might have dependencies
services.AddTransient<DonValidator>(); // of its own

services.AddTransient<ISomeProvider>(c =>
    new ConProvider(
        someValidator: c.GetRequiredService<ConValidator>(),
        otherDependency1: c:GetRequiredService<IDependency1>());

services.AddTransient<ISomeProvider>(c =>
    new DonProvider(
        someValidator: c.GetRequiredService<DonValidator>(),
        otherDependency2: c:GetRequiredService<IDependency2>());    

与第一个相比,这是一个更灵活的解决方案。但是,对构造函数的更改仍然会ConProvider迫使DonProvider您更新其注册。

为了解决这个问题,作为第三种选择,您可以使用ActivatorUtilities该类。它将帮助您实现自动装配,容器确定需要哪些依赖项。这可能看起来像这样:

services.AddTransient<ConValidator>();
services.AddTransient<DonValidator>();

services.AddTransient<ISomeProvider>(c =>
    ActivatorUtilities.CreateInstance<ConProvider>(
        c,
        c.GetRequiredService<ConValidator>());

services.AddTransient<ISomeProvider>(c =>
    ActivatorUtilities.CreateInstance<DonProvider>(
        c,
        c.GetRequiredService<DonValidator>());

ActivatorUtilities.CreateInstance将为您创建请求的课程;在这种情况下,要么ConProvider要么DonProvider。它通过查看类型的构造函数并从提供的c服务提供者解析所有构造函数参数来实现。它解析来自服务提供者的所有依赖项——除了你手动提供给该CreateInstance方法的依赖项。在上面的示例中,它将ISomeValidator依赖项与提供的DonValidator或相匹配ConValidator并注入它们。

于 2022-02-19T15:55:32.530 回答