【问题标题】:Force a class to implement an enum with no value constrain强制一个类实现一个没有值约束的枚举
【发布时间】:2018-04-10 11:48:04
【问题描述】:

我有不同的类别(例如:玩家、敌人、小行星...) - 它们应该具有不同的状态之一(例如:好的、传送...)。

enum Status
{
    Ok,
    Teleporting,
    ...
};

使用接口,我想强制这些类在其中声明仅存在枚举状态变量。但是,我希望对价值观没有限制。也就是说,玩家和敌人在状态中可以有不同的值(例如:一个可以传送,另一个不能)。

我该怎么做?

更新1

public enum Status
{
    Ok,
    Teleporting
};

public interface IHaveStatus
{
    Status Status { get; set; }
}

更新 2

public enum Status
{
    Ok,
    Teleporting
};

public interface IHaveStatus
{
    Status status;
}

【问题讨论】:

    标签: c# class enums interface


    【解决方案1】:

    除非我遗漏了一些明显的东西,否则像这样的简单界面就可以做到:

     public interface IHaveStatus
     {
          Status Status {get;}
     }
    

    值约束我会放在具体的类中。例如,如果玩家无法传送,那么在属性设置器中进行约束的好地方:

    public class Player : IHaveStatus
    {
        private Status _status;
    
        public Status Status 
        {
            get {return _status;}
            set
            {
                // a player can't teleport...
                if(value != Status.Teleport)
                {
                    _status = value;
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      你不能,至少不能使用相同的枚举类型。您必须为每组允许值声明不同的枚举。优点:您可以进行编译时检查(只要您像 Enums 值通常那样显式分配值)。缺点:你必须为每个允许的范围声明一个新的枚举。

      或者,您可以在运行时在 setter(方法或属性)中的类型级别检查传入值,并在那里强制执行任何约束。优点:您只需要一个枚举即可完成整个范围。缺点:此解决方案的缺点是您可能会遇到直到运行时才发现的错误。

      每个接受范围的解决方案枚举

      enum EnemyStatus
      {
          Ok
      }
      
      enum UserStatus
      {
          Ok,
          Teleporting
      }
      

      类型级别的解决方案约束

      class Enemy : IStatusable {
      
        public Status CurrentStatus {
          get {return _status;}
          set {if(value == Status.Teleporting) throw new NotSupportedException();
               this._status = value;
          }}
      }
      
      interface IStatusable {
         Status CurrentStatus {get;set;}
      }
      

      【讨论】:

      • 这个问题特别是关于不限制可能的值。我想你可能误读了这个问题..
      【解决方案3】:

      你可以这样声明接口:

      public interface IHaveStatus {
          Status Status { get; set; }
      }
      

      并让特定的类实现该接口:

      class Player: IHaveStatus {
          public Status Status { get; set; }
      }
      

      这不会限制状态字段的使用,它可以具有任何对Status 枚举合法的值。

      如果(但是)你想应用一些逻辑(敌人不能传送),那么这可能不是正确的设计。

      如果您想指定玩家具有某些能力(即:传送),您可以使用属性或接口来识别这些类。

      使用接口:

      public interface ICanTeleport { }
      
      public class Player : ICanTeleport { ... }
      

      您可以使用演员表确定能力:

      if(somePlayer is ICanTeleport) { .. }
      

      或使用attributes时:

      [System.AttributeUsage(System.AttributeTargets.Class)]  
      public class Teleporter : System.Attribute  
      { }
      
      [Teleporter()]
      public class Player { ... }
      

      那么你将不得不使用反射来确定属性,请参阅this question

      • 使用接口使行为绑定到类继承。它还使您能够向接口添加方法(即Teleport(coordinates) 方法)。

      • 使用属性提供了更多动态混合和匹配功能的可能性,因为没有强制功能的类层次结构。

      【讨论】:

      • 我不确定我会在界面上强制设置一个设置器,但除此之外,很好的答案! :-)
      • @ZoharPeled 嘿,这只是一个属性。随心所欲 -)
      • 只是当我写那条评论时,我们的答案除了那个细节之外都是一样的......
      • @oɔɯǝɹ 感谢您的深入回答。所以最终代码将是这样的:(参见更新后的帖子:#Update1)并且实现 IHaveStatus 接口的类将只能使用在public enum Status 中公开的全部或部分值(在这种情况下:好的和传送),但不添加新的?它是否正确?顺便说一句,在我们讨论的时候,我会回顾一下我的设计选择:)
      • @oɔɯǝɹ 为什么我不能写#Update2?
      【解决方案4】:

      如果枚举用[Flags] 属性标记,则可以在单个枚举字段中组合多个值:

      [Flags]
      enum Status
      {
          Ok = 0,
          Teleporting = 1,
          Flying = 2,
          Dancing = 4
      }
      

      然后用一个枚举属性声明接口:

      interface Base
      {
          Status Abilities { get; }
      }
      
      class Player : Base
      {
          public Status Abilities { get; set; }
      }
      

      并测试对象的不同值,如下所示:

      var p = new Player();
      p.Abilities = Status.Ok | Status.Teleporting;
      
      bool canTeleport = p.Abilities.HasFlag(Status.Teleporting);
      bool canFly = p.Abilities.HasFlag(Status.Flying);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-22
        • 2015-08-21
        • 1970-01-01
        • 2019-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-21
        相关资源
        最近更新 更多