【问题标题】:C#: Is there a way to classify enums?C#:有没有办法对枚举进行分类?
【发布时间】:2011-01-07 18:34:10
【问题描述】:

给定以下枚举:

    public enum Position
    {
        Quarterback,
        Runningback,
        DefensiveEnd,
        Linebacker
    };

是否可以对命名常量进行分类,以便我可以将“Quarterback”和“Runningback”标记为进攻位置,将“DefensiveEnd”和“Linebacker”标记为防守位置?

【问题讨论】:

  • 这是一个有趣的问题,即使它正在尝试滥用枚举,我有一个问题作为回报......你为什么不使用具有两个位置属性的 Class Player 以及他们是处于防守还是进攻团队?

标签: c# enums classification


【解决方案1】:

你可以使用属性:

public enum Position
{
    [OffensivePosition]
    Quarterback,
    [OffensivePosition]
    Runningback,
    [DefensivePosition]
    DefensiveEnd,
    [DefensivePosition]
    Linebacker
};

然后在适当的FieldInfo 上检查IsDefined。语法不是很漂亮,但是您可以添加一些扩展方法来使事情更易于管理:

public static bool IsOffensivePosition(PositionType pt)
{
    return typeof(PositionType).GetField(Enum.GetName(typeof(PositionType), pt)).
        IsDefined(typeof(OffensivePositionAttribute), false);
}

【讨论】:

  • +1 我自己在类似的情况下使用过这种方法,但我发现在枚举的情况下获取属性非常痛苦
  • 不一定很痛苦……你可以创建一个扩展方法来检索属性,每次需要的时候都可以重用它
  • 已经给了我+1,即使我确实发现反思有时是一种相当昂贵的方法来应对这种疯狂。 =)
  • @J. Steen:我同意反射位,但是如果它成为问题,您可以根据属性生成映射表,然后更改IsOffensivePosition 实现。不过,可能不是我个人选择的解决方案。
  • 嗯,是的,我想这一切都取决于你认为什么是痛苦的 :) 最后,属性摇滚! (在我的解决方案中,出于性能考虑,我最终根据类型的属性生成了一个查找表)
【解决方案2】:

你可以使用一个属性,比如CategoryAttribute

public enum Position
{
    [Category("Offensive")]
    Quarterback,
    [Category("Offensive")]
    Runningback,
    [Category("Defensive")]
    DefensiveEnd,
    [Category("Defensive")]
    Linebacker
};

【讨论】:

  • CategoryAttribute 用于对 PropertyGrid 中的属性或事件进行分组,因此可能不应滥用此类事情。 =)
  • 为什么不呢?它可以应用于任何事物,而不仅仅是属性或事件。好吧,也许它不是打算用于那个用途,但它很好地传达了预期的含义,恕我直言......
  • System.ComponentModel.CategoryAttribute 已经有了用处 - 对我来说,它传达的含义与预期完全不同。
  • 这是个好主意...但是采用辅助枚举的自定义属性可能比字符串值更好。
【解决方案3】:

为什么不接吻:

class PlayerPosition {
    public enum Position {
        Quarterback,
        Runningback,
        DefensiveEnd,
        Linebacker
    }

    public enum Type {
        Offense,
        Defense
    }


    public static Type GetTypeForPosition(Position position) {
        switch (position) {
            case Quarterback:
            case Runningback:
                return Type.Offense;
            case DefensiveEnd:
            case Linebacker:
                return Type.Defense;

        }
    }
}

【讨论】:

  • 您可能想使用除 Type 以外的枚举名称,并使用 System.Type 等。每次使用时都消除歧义真的很烦人。 :)
【解决方案4】:
public enum PositionType
{
    Offensive,
    Defensive,
}

public class PositionTypeAttribute : Attribute
{
    public PositionTypeAttribute(PositionType positionType)
    {
        PositionType = positionType;
    }
    public PositionType PositionType { get; private set; }
}

public enum Position
{
    [PositionType(PositionType.Offensive)]
    Quarterback,
    [PositionType(PositionType.Offensive)]
    Runningback,
    [PositionType(PositionType.Defensive)]
    DefensiveEnd,
    [PositionType(PositionType.Defensive)]
    Linebacker
};

public static class PositionHelper
{
    public static PositionType GetPositionType(this Position position)
    {
        var positionTypeAttr = (PositionTypeAttribute)typeof(Position).GetField(Enum.GetName(typeof(Position), position))
            .GetCustomAttributes(typeof(PositionTypeAttribute), false)[0];
        return positionTypeAttr.PositionType;

    }
}


Position position1 = Position.Runningback;
Console.WriteLine(position1.GetPositionType()); //print: Offensive

Position position2 = Position.Linebacker;
Console.WriteLine(position2.GetPositionType()); //print: Defensive

【讨论】:

  • +1 技术的终极组合。一个枚举为用于装饰另一个枚举的成员值的属性提供参数。
  • 是的:) 而且扩展方法大大简化了使用。
  • 这个帮助很大,谢谢!特别是因为您的代码很干净并且满足我们需要这种安排的所有情况。
【解决方案5】:

你可以使用Flags

[Flags]
public enum Position
    {
        Quarterback = 1,
        Runningback = 2,
        DefensiveEnd = 4,
        Linebacker = 8,

        OffensivePosition = Quarterback | Runningback,
        DefensivePosition =  Linebacker | DefensiveEnd, 

    };

    //strictly for example purposes
    public bool isOffensive(Position pos)
    {
        return !((pos & OffensivePosition) == pos);
    }

【讨论】:

  • 您想阐明您对 Flags 如何解决提问者问题的想法吗?
  • 当使用[Flags] 时,您还应该指定以2 的幂为单位的枚举常量。
  • 我同意你应该这样做,但你不必明确这样做
  • -1:正如发布的那样,这根本不起作用。 Quarterback 将为零,RunningbackOffensivePositions1
  • 这似乎是迄今为止最简单的解决方案。 (正确设置值)
【解决方案6】:

也许你可以尝试使用typesefe enum pattern

class Position
{
    public bool Offensive { get; private set; }
    public bool Defensive { get; private set; }

    private Position()
    {
        Offensive = false;
        Defensive = false;
    }

    public static readonly Position Quarterback = new Position() { Offensive = true };
    public static readonly Position Runningback = new Position() { Offensive = true };
    public static readonly Position DefensiveEnd = new Position() { Defensive = true };
    public static readonly Position Linebacker = new Position() { Defensive = true };
}

【讨论】:

  • %s/私人职位/私人职位/g
【解决方案7】:

您可以使用某种形式的标志位。但这可能会导致混乱。更好的方法可能是只使用您想要的详细信息创建自定义类,然后使用字典来查找每种职位类型;

public class PlayerPosition {
    public PlayerPosition (string positionName, bool isDefensive ) {
        this.Name = positionName;
        this.IsDefensive = isDefensive ;
    }
    public string Name { get; private set; }
    public bool IsDefensive { get; private set; }
}

...作为枚举...

[Flags]
public enum Positions {
    Quarterback = 0x21, 
    Runningback = 0x22, 
    DefensiveEnd = 0x14, 
    Linebacker = 0x18, 

    Defensive = 0x10,
    Offsensive = 0x20
}

【讨论】:

    【解决方案8】:

    一种未充分利用(但完全有效)的技术是使用定义一组常量的类。作为一个类,您可以添加其他属性来描述枚举值的其他方面。奇怪的是,这是大多数枚举在 Java 中实现的方式(没有特殊的关键字)。

    如果你走这条路,通常最好将类密封并定义一个私有构造函数,这样只有类本身才能定义实例。这是一个例子:

    public static class Position 
    {
        private PlayerPosition (string name, bool isDefensive ) {
            this.Name = name
            this.IsDefensive = isDefensive ;
        }
        // any properties you may need...
        public string Name { get; private set; }
        public bool IsDefensive { get; private set; }
        public bool IsOffensive { get { return !IsDefensive; } }
    
        // static instances that act like an enum
        public static readonly Quarterback = new PlayerPosition( "Quarterback", false );
        public static readonly Runningback = new PlayerPosition( "Runningback", false );
        public static readonly Linebacker = new PlayerPosition( "Linebacker", true );
        // etc...
    }
    

    使用这样的枚举会产生比属性更优雅、更简单的语法:

    if( PlayerPosition.Quarterback.IsDefensive )
    {
        // ...
    }
    

    【讨论】:

      【解决方案9】:

      你可以在一个类中声明枚举:

      public class Position
      {
          public enum Offensive { Quarterback = 1, RunningBack }
          public enum Defensive { DefensiveEnd = 10, LineBacker }
      }
      

      请注意,防御值从 10 开始,因此值不会重叠。您没有说明为什么要这样做,因此这可能无法满足您的需求。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-17
        • 2011-10-01
        • 2011-06-26
        • 1970-01-01
        • 2016-07-24
        相关资源
        最近更新 更多