【问题标题】:Enum with methods for functionality (Combine Class / Enum)具有功能方法的枚举(组合类/枚举)
【发布时间】:2011-09-16 10:08:48
【问题描述】:

如果是这种情况,我可能会在这里遗漏一些要点 - 请将该讨论作为我的问题的一部分:)。

这是一个缩短并重命名的工作代码示例。 GetTicks(…) 是单个样本,可以是任何类型的功能(> 0 < 9 的值应返回特定的 Enum a.so)。

public static class Something
{
    public enum TypeOf : short
    {
        Minute = 2, Hour = 3, Day = 4, …
    }

    public static long GetTicks(Something.TypeOf someEnum)
    {
        long ticks = 0;
        switch (someEnum)
        {
            case Something.TypeOf.Minute:
                ticks = TimeSpan.TicksPerMinute;
                break;
            case Something.TypeOf.Hour:
                ticks = TimeSpan.TicksPerHour;
                break;
         ....
        }
        return ticks;
    }
}

// This class is called from anywhere in the system.
public static void SomeMethod(string dodo, object o, Something.TypeOf period)
{
    // With the design above
    long ticks = Something.GetTicks(period);

    // Traditional, if there was a simple enum
    if (period == Something.Day)
        ticks = TimeSpan.FromDays(1).Ticks;
    else if (period == Something.Hour)
        ticks = TimeSpan.FromHours(1).Ticks;
}

这个想法是收集与enum 相关的功能,尽可能靠近enum 本身。 enum 是原因函数。另外,我发现在enum 附近寻找这样的功能很容易也很自然。此外,它很容易修改或扩展。

我的缺点是我必须更明确地说明enum,例如Something.TypeOf。设计可能看起来不标准?如果enum 供班级内部使用,它是否适用。

你会如何做得更好? 我试过abstract,基本继承,partial。它们似乎都不适用。

【问题讨论】:

    标签: c#


    【解决方案1】:

    如果您不介意多写一点,您可以制作扩展方法来扩展enum 的接口。

    例如

    public enum TimeUnit
    {
       Second,
       Minute,
       Hour,
       Day,
       Year,
       /* etc */
    }
    public static class TimeUnitExtensions
    {
        public static long InTicks(this TimeUnit myUnit)
        {
             switch(myUnit)
             {
               case TimeUnit.Second:
                   return TimeSpan.TicksPerSecond;
               case TimeUnit.Minute:
                   return TimeSpan.TicksPerMinute;
                /* etc */
             }
        }
    }
    

    这可以为您的枚举添加“实例”方法。不过,它比大多数人喜欢的要冗长一些。

    请记住,enum 应该主要被视为命名值。

    【讨论】:

    • 您如何将TimeUnitExtensionsTimeUnit 以及您想要其刻度的TimeSpan 实例联系起来?我可能缺少一些上下文,毫无疑问我缺乏 C# 知识并没有帮助。
    • @DavidHarkness,这是因为这一行中的“this”:public static long InTicks(this TimeUnit myUnit)。 "this" 将 TimeUnit 关联到扩展。
    • 我喜欢乔恩的回答,但这也是一种可能。 +1,我没有考虑过扩展方法!
    • 这个结合了枚举的快速性和扩展方法的优雅。太糟糕了,没有扩展属性。 ☹
    【解决方案2】:

    C# 枚举不能像这样很好地工作。但是,您可以相当轻松地实现自己的“固定值集”:

    public sealed class Foo
    {
        public static readonly Foo FirstValue = new Foo(...);
        public static readonly Foo SecondValue = new Foo(...);
    
        private Foo(...)
        {
        }
    
        // Add methods here
    }
    

    碰巧,我得到的一个例子与你的非常相似 - Noda Time 中的 DateTimeFieldType。有时您甚至可能希望使类未密封,但保留私有构造函数 - 它允许您创建子类仅作为嵌套类。对于限制继承非常方便。

    缺点是不能使用 switch :(

    【讨论】:

    • 确实,非常相似!我喜欢你的方法,当我知道有时间进行优化并了解它的好处(如果有的话)时,我会深入研究它;))。
    • 是的,类似 Java 的枚举。虽然我建议使用结构,而不是类。还有一个用于快速比较的 Value 字段和 switch 语句。
    • @Andrei:是的。我可能会写一个单元测试来用反射来验证它:)
    • 为什么要使用这个公认答案的方法而不是为 Enum 类提供扩展方法?我只是想知道我自己的知识。它似乎提供了完全相同的功能。
    • @RichieEpiscopo:使用枚举,你仍然只有那个单一的值。所以实现这些扩展方法可能很痛苦;你不能使用任何正常的 OO 技术,或者有任何状态等。
    猜你喜欢
    • 2020-03-03
    • 1970-01-01
    • 2020-07-26
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多