.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>>();
我目前正在学习 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>>();