.NET 上的依赖注入:DI 框架如何 return 基于条件的对象

Dependency Injection on .NET: how DI framework can return objects based on conditions

我目前正在学习 DI 并进行试验。这是我的练习代码和概述,我正在做的就像模仿一个驾驶模拟器游戏,玩家的车库里有两辆车:本田和丰田。而且玩家先用本田,再换丰田,再换回本田。

using Microsoft.Extensions.DependencyInjection;
using System;
using Microsoft.Extensions.Hosting;
using static System.Guid;

namespace ConsoleApp2
{
    // ----------- CARS 
    public interface ICar
    {
        string Description { get; }
    }

    public class Honda : ICar
    {
        private string Id = NewGuid().ToString()[^4..]; // just to see if instance has changed
        public string Description => "HONDA " + Id;
    }

    public class Toyota : ICar
    {
        private string Id = NewGuid().ToString()[^4..]; // just to see if instance has changed
        public string Description => "TOYOTA " + Id;
    }


    // ----------- CAR FACTORY

    public enum CarType
    {
        Unknown,
        Honda,
        Toyota
    }

    public interface ICarFactory
    {
        CarType CarType { set; }
        ICar GetCar();
    }


    public class CarFactory : ICarFactory
    {
        ICar _car;
        CarType _carType = CarType.Unknown;

        public CarType CarType 
        {
            set
            {
                if(_carType != value)
                {
                    switch (value)
                    {
                        case CarType.Honda: _car = new Honda(); break;
                        case CarType.Toyota: _car = new Toyota(); break;
                        default: throw new NotImplementedException();
                    }
                    _carType = value;
                }
            }
                
        }
        public ICar GetCar() { return _car; }
    }


    // ----------- MAIN

    class Program
    {
        static void Main(string[] args)
        {
            using IHost host = Host.CreateDefaultBuilder(args)
                .ConfigureServices((_, services) =>
                    services.AddSingleton<ICarFactory, CarFactory>())
                .Build();

            // --------------
            ChooseCar(host.Services, CarType.Honda); // user chooses Honda

            // lets say a user changed a configuration and wants to use Toyota all through
            ChooseCar(host.Services, CarType.Toyota);

            // lets say a user changed a configuration and wants to use the same Honda (previous selection)
            ChooseCar(host.Services, CarType.Honda);
        }

        static void ChooseCar(IServiceProvider services, CarType c)
        {
            using IServiceScope serviceScope = services.CreateScope();
            IServiceProvider provider = serviceScope.ServiceProvider;
            var carfactory = provider.GetRequiredService<ICarFactory>();
            carfactory.CarType = c;
            Console.WriteLine("Using:" + carfactory.GetCar().Description);
            Console.WriteLine("Using:" + carfactory.GetCar().Description);
        }
    }
}

这是输出:

Using:HONDA 6573
Using:HONDA 6573
Using:TOYOTA c20f
Using:TOYOTA c20f
Using:HONDA b537
Using:HONDA b537

根据此输出,最后一部分的 returned Honda 与第一部分的实例不同,但是,玩家想要以前的 Honda。现在,我可以让工厂 handle/remember 实例以确保它将 return 以前的本田。但是,我认为 Factory 做的比它应该做的更多,我想知道 DI 框架是否可以在这方面提供帮助?如果我继续这个想法,工厂将完成处理 ICar 先前实例的大部分工作。我只是希望工厂只负责生产新车,而不是记住以前是否生产过。

DI要是有什么可以帮助消灭工厂的,那就更好了。 我现在在想的是,每次更改设置时调用下面的代码,并将 ICar 更改为 return 丰田或本田,但每次都创建构建器并重新配置服务是一种不好的做法?

         using IHost host = Host.CreateDefaultBuilder(args)
        .ConfigureServices((_, services) =>
            services.AddSingleton<ICar, Honda>()) // or Toyota, depending on what is needed
        .Build();

此外,如果我这样做,我将如何处理车库中有两辆或多辆丰田(或本田)的情况(例如,有丰田 RAV-4 和丰田普锐斯,可能有不同的 class 对于 ToyotaPrius 和 ToyotaRav4)?

基本上,我的最终目标是根据用户选择将 DI 直接投资到 return 本田或丰田,如果可能的话,不使用工厂。

我曾经使用这种方法解决多个实施问题:

public interface ICar
{

}

public class Honda : ICar { }
public class Toyota : ICar { }

public interface ICarProvider<TCar> where TCar : ICar
{
    ICar ProvideCar();
}

public class CarProvider<TCar> : ICarProvider<TCar> where TCar : ICar, new()
{
    private ICar _car;
    public ICar ProvideCar()
    {
        if (_car == null)
        {
            _car = new TCar();
        }

        return _car;
    }
}

然后在你的启动中,你需要有这个:

        services.AddSingleton<ICarProvider<Toyota>, CarProvider<Toyota>>();
        services.AddSingleton<ICarProvider<Honda>, CarProvider<Honda>>();