具有从同一接口继承的类的依赖性注入Console .Net Core

时间:2019-02-17 20:18:15

标签: c# dependency-injection .net-core console-application

我正在使用.Net Core控制台应用程序处理两个类(GenerateCsv,GenerateTxt),它们从同一接口(GenerateFile)继承。它们都采用IReadFile,IWriteFile接口作为构造函数参数。

我想使用依赖注入创建正确的类来生成文件并在完成后返回字符串值。

static void Main()
    {
        string result="Processed Nothing";

        Console.WriteLine("To Generate: \n");
        Console.WriteLine("1) English CSV File Type 1 \n"+
                          "2) Englsih Txt File Type 2 \n" +
                          "3) To Exit Type 3 \n");

        var userInput = Convert.ToInt32(Console.ReadLine());

        if (userInput == 10)
            Environment.Exit(0);

        var service = BuildDependencies.Build();

        Console.WriteLine("Started Generating");
        Console.WriteLine("Working, please wait");

        switch (userInput)
        {
            case 1:
                result = service.GetService<IGenerateFile>().GenerateFile();
                break;
            case 2:
                result = service.GetService<IGenerateFile>().GenerateFile();
                break;
        }
        Console.WriteLine(result);

BuildDependencies类

using Microsoft.Extensions.DependencyInjection;
public static class BuildDependencies
{
    public static ServiceProvider Build()
    {
        var services = new ServiceCollection()
            .AddTransient<IReadFile, ReaFile>()
            .AddTransient<IWriteFile, WriteFile>()
            .AddTransient<IGenerateFile,GenerateCsv>()
            .AddTransient<IGenerateFile,GenerateTxt>()
            .BuildServiceProvider();

        return services;
    }

2 个答案:

答案 0 :(得分:1)

您应将switch(userinput)块替换为对工厂类的调用。

该班级的合同可能类似于:

interface IFileGeneratorFactory
{
    // I used int because it's in your example code, but an enum would be a stronger contract
    IGenerateFile GetFileGenerator(int userInput);
}

和类似的实现:

class FileGeneratorFactory : IFileGeneratorFactory
{
    readonly IServiceProvider serviceProvider;

    public FileGeneratorFactory(IServiceProvider serviceProvider)
        => this.serviceProvider = serviceProvider;

    public IGenerateFile GetFileGenerator(int userInput)
    {
        switch (userInput)
        {
            // The Factory has explicit knowledge of the different generator types,
            // but returns them using a common interface. The consumer remains
            // unconcerned with which exact implementation it's using.
            case 1:
                return serviceProvider.GetService<GenerateCsv>();
            case 2:
                return serviceProvider.GetService<GenerateTxt>();
            default:
                throw new InvalidOperationException($"No generator available for user input {userInput}");
        }
    }
}

注册类似的类:

var services = new ServiceCollection()
    .AddTransient<GenerateCsv>()
    .AddTransient<GenerateTxt>()
    .AddTransient<IFileGeneratorFactory, FileGeneratorFactory>();

然后,像这样消费:

IGenerateFile fileGenerator = service
    .GetService<IFileGeneratorFactory>()
    .GetFileGenerator(userInput);

string result = fileGenerator.GenerateFile();

此工厂实现非常简单。我以这种方式编写它以使其易于使用,但我强烈建议您查看Simple Injector docs中更优雅的示例。由于这些示例针对的是Simple Injector,而不是ASP.Net DI,因此可能需要进行一些调整才能为您工作-但基本模式应适用于任何DI框架。

答案 1 :(得分:0)

您可以创建两个界面

interface IGenerateCsv : IGenerateFile{}
interface IGenerateTxt: IGenerateFile{}

然后同时向您的DI供应商注册:

public static ServiceProvider Build()
{
    var services = new ServiceCollection()
        .AddTransient<IReadFile, ReaFile>()
        .AddTransient<IWriteFile, WriteFile>()
        .AddTransient<IGenerateCsv ,GenerateCsv>()
        .AddTransient<IGenerateTxt,GenerateTxt>()
        .BuildServiceProvider();

    return services;
}

然后,您可以创建另一个具有两个实例并确定要调用的类的类。然后将该类注入您的消费者中。

enum OutputType
{
    Csv,
    Text
}

interface IFileGenerator
{
    void GenerateFile(OutputType outputType);
}

class FileGenerator : IFileGenerator
{
    // inject both or your file services into the constructor


    public void GenerateFile(OutputType outputType)
    {
         switch(outputType)
         {
              // call the correct service here
         }
    }

然后注册IFileGenerator

public static ServiceProvider Build()
{
    var services = new ServiceCollection()
    .AddTransient<IReadFile, ReaFile>()
    .AddTransient<IWriteFile, WriteFile>()
    .AddTransient<IGenerateCsv ,GenerateCsv>()
    .AddTransient<IGenerateTxt, GenerateTxt>()
    .AddTransient<IFileGenerator, FileGenerator>()
    .BuildServiceProvider();

    return services;
}

在您的消费者类中执行以下操作:

class Consumer
{
    private readonly IFileGenerator fileGenerator;

    Consumer(IFileGenerator, fileGenerator)
    {
        this.fileGenerator = fileGenerator;
    }

    public void SomeMethod(string userInput)
    {
          switch(userInput)
          {
                case 1: 
                    fileGenerator.GenerateFile(OutputType.Csv);
                    break;

                case 2: 
                    fileGenerator.GenerateFile(OutputType.Text);
                    break;

                default:
                    break;
          }
    }
}

那是假设您具有某种消费类。如果您只是在使用Main方法,请执行以下操作:

var serviceProvider = BuildDependencies.Build();
var fileGenerator = serviceProvider.GetService<IFileGenerator>();