C# 枚举类模式是否与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

在进入DI之前,我非常喜欢使用所谓的enum类(或我头脑中的强enum),其中枚举被转换为类,但设置为以类似于enum的方式使用。这使真正属于特定枚举的逻辑能够封装在正确的位置,并防止代码库中出现大量混乱

这里就是一个例子

一旦你把DI引入到方程中,尽管它会因为依赖静态变量而变得有问题

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=