C# 枚举类模式是否与DI不兼容?
在进入DI之前,我非常喜欢使用所谓的enum类(或我头脑中的强enum),其中枚举被转换为类,但设置为以类似于enum的方式使用。这使真正属于特定枚举的逻辑能够封装在正确的位置,并防止代码库中出现大量混乱 这里就是一个例子 一旦你把DI引入到方程中,尽管它会因为依赖静态变量而变得有问题C# 枚举类模式是否与DI不兼容?,c#,.net,dependency-injection,ioc-container,simple-injector,C#,.net,Dependency Injection,Ioc Container,Simple Injector,在进入DI之前,我非常喜欢使用所谓的enum类(或我头脑中的强enum),其中枚举被转换为类,但设置为以类似于enum的方式使用。这使真正属于特定枚举的逻辑能够封装在正确的位置,并防止代码库中出现大量混乱 这里就是一个例子 一旦你把DI引入到方程中,尽管它会因为依赖静态变量而变得有问题 public class EmployeeType : Enumeration { public static readonly EmployeeType Manager = new M
public class EmployeeType : Enumeration
{
public static readonly EmployeeType Manager
= new ManagerType (0, "Manager");
public static readonly EmployeeType Servant
= new EmployeeType(1, "Servant");
public static readonly EmployeeType AssistantToTheRegionalManager
= new EmployeeType(2, "Assistant to the Regional Manager");
private EmployeeType() { }
private EmployeeType(int value, string displayName) : base(value, displayName) { }
}
public class ManagerType : EmployeeType
{
}
有没有办法继续支持这种模式并使用DI
编辑:
下面是一个类型的示例,如果我想向EmployeeType中注入一些新的东西,那么这个类型就有问题。由于静态变量,我无法使用容器
public class EmployeeType : Enumeration
{
public static readonly EmployeeType Manager
= new ManagerType (0, "Manager");
public static readonly EmployeeType Servant
= new EmployeeType(1, "Servant");
public static readonly EmployeeType AssistantToTheRegionalManager
= new EmployeeType(2, "Assistant to the Regional Manager");
private EmployeeType() { }
private EmployeeType(int value, string displayName) : base(value, displayName) { }
}
public class ManagerType : EmployeeType
{
}
您可以在enum类中使用单例。我想您可以在这里使用。您可以保留枚举类型,也可以使用任何可以帮助您识别策略的类型(在我的示例中,我将使用string)。然后为每个值实施一个策略
interface IEmployeeHandler
{
string EmployeeType { get; }
void Handle(Employee employee);
}
class ManagerHandler : IEmployeeHandler
{
public ManagerHandler()
{
EmployeeType = "Manager";
}
public string EmployeeType { get; private set; }
public void Handle(Employee employee) { }
}
class ServantHandler : IEmployeeHandler
{
public ServantHandler()
{
EmployeeType = "Servant";
}
public string EmployeeType { get; private set; }
public void Handle(Employee employee) { }
}
由于DI容器可以注入接口的多个实现,因此您可以编写如下策略提供程序类:
class EmployeeStrategyProvider
{
private readonly IEmployeeHandler[] _employeeHandlers;
public EmployeeStrategyProvider(IEmployeeHandler[] employeeHandlers)
{
_employeeHandlers = employeeHandlers;
}
public IEmployeeHandler GetStrategy(string employeeType)
{
return _employeeHandlers.FirstOrDefault(item => item.EmployeeType == employeeType);
}
}
您可以使用此类根据员工类型获取正确的策略。这就是我如何用DI容器实现策略模式。不过,我认为它可以做一些改进
我很高兴听到一些建议。我自己使用这个模式已经有一段时间了,但从未考虑过向其中注入服务的必要性。但是,嘿,这应该是可能的,对吗 一种解决方案是延迟创建依赖于服务实例的任何枚举,直到需要它们为止——其他一切看起来和行为都像常规静态类型 下面是
EmployeeType
类,它添加了依赖于IBonusService
的Manager
的延迟实例化:
public class EmployeeType : Enumeration
{
public static Func<IBonusService> BonusService { private get; set; }
private static EmployeeType _manager = null;
public static EmployeeType Manager {
get
{
if (_manager == null) _manager = new ManagerType(BonusService());
return _manager;
} }
public static readonly EmployeeType Servant
= new EmployeeType(1, "Servant");
public static readonly EmployeeType AssistantToTheRegionalManager
= new EmployeeType(2, "Assistant to the Regional Manager");
private EmployeeType(int value, string displayName) :
base(value, displayName) { }
public virtual decimal BonusSize { get { return 0; } }
private class ManagerType : EmployeeType
{
private readonly IBonusService service;
public ManagerType(IBonusService service) : base(0, "Manager")
{
this.service = service;
}
public override decimal BonusSize {
get { return this.service.currentManagerBonus; } }
}
}
公共类EmployeeType:枚举
{
public static Func BonusService{private get;set;}
私有静态EmployeeType_manager=null;
公共静态EmployeeType管理器{
得到
{
如果(_manager==null)_manager=newmanagerType(BonusService());
返回(u经理),;
} }
公共静态只读EmployeeType服务
=新雇员类型(1,“仆人”);
公共静态只读EmployeeType AssistantToTheRegionalManager
=新员工类型(2,“区域经理助理”);
私有EmployeeType(int值,字符串显示名称):
基(值,显示名){}
公共虚拟十进制BonuSize{get{return 0;}}
私有类管理器类型:EmployeeType
{
专用只读IBonusService服务;
公共管理器类型(IBonusService服务):基本(0,“管理器”)
{
服务=服务;
}
公共覆盖十进制BonuSize{
获取{返回this.service.currentManagerBonus;}}
}
}
您可以在合成根目录中配置依赖项:
[Test]
public void EmployeeType_Manager_HasBonusService()
{
Container container = new Container();
container.Register<IBonusService, BonusServiceStub>();
EmployeeType.BonusService = () => container.GetInstance<IBonusService>();
BonusServiceStub.constructed = false;
container.Verify();
//Verify has ensured the container can create instances of IBonusService
Assert.That(BonusServiceStub.constructed, Is.True);
EmployeeType manager = EmployeeType.Manager;
Assert.That(manager.BonusSize == 999m);
}
public class BonusServiceStub : IBonusService
{
public static bool constructed = false;
public BonusServiceStub() { constructed = true; }
public decimal currentManagerBonus { get { return 999m; } }
}
[测试]
public void EmployeeType_Manager_HasBonusService()
{
容器=新容器();
container.Register();
EmployeeType.BonusService=()=>container.GetInstance();
BonusServiceStub.constructed=false;
container.Verify();
//验证已确保容器可以创建IBonusService的实例
Assert.That(BonusServiceStub.constructed,Is.True);
EmployeeType manager=EmployeeType.manager;
断言(manager.BonusSize==999m);
}
公共类BonusServiceStub:IBonusService
{
公共静态bool constructed=false;
public BonusServiceStub(){constructed=true;}
公共十进制currentManagerBonus{get{return 999m;}}
}
专门注入
Func
而不是IBonusService
的原因是,服务的生命周期范围(以及装饰等)在组合根中进行管理,并保持独立于使用者。与常规继承或策略模式相比,此模式的优势是什么(两者都没有这个问题)?我认为熟悉/可用性以及从枚举迁移到枚举类的容易程度(即相同地使用)。请给出一个示例,说明您正在做什么,以及在与DI结合时出现问题的地方。如果基本上是硬编码的,为什么您需要DI?您没有将DI与标准枚举一起使用,对吗?这不是我的实际代码,但坚持这个假示例,假设我后来想注入一些工厂或其他工厂,因为我需要d公开EmployeeType接口中的某些内容。我确实想到了这一点,但我不清楚如何创建该单例并注入依赖项,但再仔细考虑一下,我想如果在CompositionRoot中创建该单例,那么它可能就行了。我想枚举c的每个子类型都需要一个单例lass如果有。例如ManagerType over是不幸的是,您必须为每个子类实现singleton。是否有方法仍然保留EmployeeType.Manager枚举样式符号。您是否将上述内容与singleton结合使用(参见B3ret的答案)?这是个好主意吗?@Ian1971可以这样做,但我认为这是不必要的。您仍然需要在代码中使用一些数据创建一个“枚举类型”的实例。只需将这些数据包含在策略界面中,您就可以在没有这些静态实例的情况下使其工作。好的,这很有意义。我喜欢您的实现。所以我认为perhaps我的问题“enum类模式是否与di不兼容?”确实不是,但最好用战略模式来代替。我不能说这是不兼容的。他们当然可以一起工作,但我认为这是多余的。虽然我在这里没有权威,但你可以为你的案例做出最佳决策。这很好。我想知道的一件事是,这个EmployeeType.BonusService=