在设计模式中替代枚举

时间:2016-08-09 16:21:12

标签: c# .net design-patterns enums

考虑具有base类型的基本程序集enum的情况,如

public enum ItemState = { red, green, blue };

我在其他程序集Project_1Project_2等中使用此基本程序集。

他们每个人都会做一些特定的事情,并且需要特定于项目的状态,例如{grey, black, white, ...}中的Project_1{brown, transparent, ...}中的Project_2

Project_1不允许使用(如果可能,甚至可以查看){brown, transparent, ...}。同样,Project_2无法使用{grey, black, white, ...}

我知道"部分枚举"不存在 - 那么这个任务的建议设计模式是什么?

3 个答案:

答案 0 :(得分:6)

由于枚举不能继承,一个解决方案可能是使用具有静态常量成员的类,如下所示:

public class ItemState
{
    protected ItemState() { }

    public static ItemState red { get; } = new ItemState();
    public static ItemState green { get; } = new ItemState();
    public static ItemState blue { get; } = new ItemState();
}

然后在你的Project_1中,你可以得到一个自己的类:

public class ItemState_1 : ItemState
{
    public static ItemState grey { get; } = new ItemState_1();
    public static ItemState black white { get; } = new ItemState_1();
}

并在Project_2

public class ItemState_2 : ItemState
{
    public static ItemState brown { get; } = new ItemState_2();
    public static ItemState transparent white { get; } = new ItemState_2();
}

这可能不是最舒服的方式,但我现在能想到的最好的方式。

你可以这样使用它们:

ItemState project1State = ItemState_1.grey;

if (project1State == ItemState_1.grey)
   // do something

这一切都很好,但不幸的是这些值不能用在switch/case语句中。这可以通过适当的ToString()实现来解决,字符串文字可以在switch/case中使用。但这当然会为这些类/属性定义添加更多代码。

答案 1 :(得分:4)

我有点迟了,但这里是Rene回答的“buffed”版本(现在有隐式演员!):

public class ColorEnum
{
    protected readonly string Name;
    protected readonly Color Value;

    public static readonly ColorEnum Red = new ColorEnum(Color.Red, "Red");
    public static readonly ColorEnum Green = new ColorEnum(Color.Green, "Green");
    public static readonly ColorEnum Blue = new ColorEnum(Color.Blue, "Blue");

    protected ColorEnum(Color value, string name)
    {
        Name = name;
        Value = value;
    }

    public override string ToString()
    {
        return Name;
    }

    public static implicit operator Color(ColorEnum @enum)
    {
        return @enum.Value;
    }

    public static implicit operator string(ColorEnum @enum)
    {
        return @enum.Name;
    }
}

public class AnotherColorEnum : ColorEnum
{
    public static readonly ColorEnum Grey = new AnotherColorEnum(Color.Gray, "Grey");
    public static readonly ColorEnum Black = new AnotherColorEnum(Color.Black, "Black");
    public static readonly ColorEnum White = new AnotherColorEnum(Color.White, "White");

    protected AnotherColorEnum(Color value, string name) : base(value, name)
    {
    }
}

这样你就可以像这样使用“enum”:

    var color = ColorEnum.Red;
    var anothercolor = Color.Red;
    if (color == anothercolor)
    {
            //DoSomething
    }

或者像这样:

    var color = ColorEnum.Red;
    var anothercolor = "Red";
    if (color == anothercolor)
    {
            //DoSomething
    }

答案 2 :(得分:1)

根据您的使用情况,您可能希望使用主/子集模式。

例如,我有一个包含所有可能值的枚举:

--Create table structure
create table #stock (IMS_Number varchar(10), InStocked int)
go

create table #request (requestID int identity(1,1), IMS_Number varchar(10), Requested int, RequestDate date)
go


--Insert into sample Data
insert #stock values ('H000092229', 3),('H111108880',8)

insert #request 
select 'H000092229', 2, '08-09-2016'
union all
select 'H000092229', 3, '08-09-2016'
union all
select 'H000092229', 3, '08-09-2016'
union all
select 'H000092229', 3, '08-09-2016'
union all
select 'H000092229', 1, '08-09-2016'

select * from #stock
select * from #request


--Below is the solution
select 
    IMS_number, 
    Requested, 
    case    when RID = 1 
            then instocked 
            else LAG(instockReal,1,0)over(order by requestid) 
    end as InStocked
from
(
    select  b.requestid, 
            a.instocked, 
            b.IMS_number, 
            b.requested, 
            sum(b.requested)over(partition by b.IMS_number order by b.requestid) * (-1) + a.instocked as instockReal,
            row_number()over(partition by b.ims_number order by requestid) as RID
    from #request b
    join #stock a
    on b.IMS_Number = a.IMS_Number
) as ab

然后每个项目都有自己的值子集:

/// <summary>
/// Types of limits that can be applied to a table, view, or table-value function query.
/// </summary>
/// <remarks>Databases are expected to provide their own enumeration that represents a subset of these options.</remarks>
[Flags]
public enum LimitOptions
{
    /// <summary>
    /// No limits were applied.
    /// </summary>
    None = 0,

    /// <summary>
    /// Returns the indicated number of rows with optional offset
    /// </summary>
    Rows = 1,

    /// <summary>
    /// Returns the indicated percentage of rows. May be applied to TableSample
    /// </summary>
    Percentage = 2,


    /// <summary>
    /// Adds WithTies behavior to Rows or Percentage
    /// </summary>
    WithTies = 4,


    /// <summary>
    /// Returns the top N rows. When there is a tie for the Nth record, this will cause it to be returned. 
    /// </summary>
    RowsWithTies = Rows | WithTies,

    /// <summary>
    /// Returns the top N rpercentage of ows. When there is a tie for the Nth record, this will cause it to be returned. 
    /// </summary>
    PercentageWithTies = Percentage | WithTies,

子项目总是使用严格的子集,而不是使枚举可扩展。这允许我保持核心相当通用,同时在适当的时候提供数据库特定的API。