【问题标题】:Alternative to enum in design pattern设计模式中枚举的替代方案
【发布时间】:2016-12-15 19:19:04
【问题描述】:

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

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

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

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

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

我知道“部分枚举”不存在 - 那么此类任务的建议设计模式是什么?

【问题讨论】:

  • Related, maybe dupe?(超越公认的答案寻找替代方案)
  • 你可以使用 2 个枚举吗?如果不是,为什么只需要访问一些值?我认为没有关于此的设计模式,而且在您的模型中似乎更像是错误的选择。

标签: c# .net design-patterns enums


【解决方案1】:

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

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

/// <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,

那么每个项目都有自己的价值子集:

/// <summary>
/// Limit options supported by Access.
/// </summary>
/// <remarks>This is a strict subset of LimitOptions</remarks>
public enum AccessLimitOption
{
    /// <summary>
    /// No limits were applied.
    /// </summary>
    None = LimitOptions.None,

    /// <summary>
    /// Uses TOP
    /// </summary>
    RowsWithTies = LimitOptions.RowsWithTies,

}

子项目始终使用严格的子集,而不是使枚举可扩展。这使我能够保持核心相当通用,同时在适当的情况下提供特定于数据库的 API。

【讨论】:

    【解决方案2】:

    我有点晚了,但这里是 Rene 答案的“抛光”版本(现在带有隐式转换!):

    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)
        {
        }
    }
    

    这样你就可以像这样使用你的“枚举”:

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

    或者像这样:

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

    【讨论】:

    • 很好,现在如果你有一个ColorEnum ce,你可以做一个switch(ce.ToString()) case "Grey":....,它看起来仍然不完美,但可以工作(case ColorEnum.Grey.ToString() 不会编译)。
    • 我最终使用了你的答案 René。请注意,与枚举一样,on 可以在类中使用常量“int”值,然后可以将其切换/case on...!
    • 真的想将其用作属性参数,但得到“属性参数必须是属性参数类型的常量表达式、typeof 表达式或数组创建表达式” -有什么方法可以将其引入这些要求?看到这个SO
    【解决方案3】:

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

    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!!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 2012-09-19
    相关资源
    最近更新 更多