C# 强制类实现无值约束的枚举

C# 强制类实现无值约束的枚举,c#,class,enums,interface,C#,Class,Enums,Interface,我有不同的职业(例如:玩家,敌人,小行星…),它们应该有不同的状态(例如:ok,传送…) 使用接口,我想强制这些类只声明它们内部枚举状态变量的存在。但是,我希望对值没有限制。也就是说,玩家和敌人在状态中可以有不同的值(例如:一个可以传送,另一个不能) 我该怎么做 更新1 更新2 您可以按如下方式声明接口: public interface IHaveStatus { Status Status { get; set; } } 并让特定类实现该接口: class Player: IHav

我有不同的职业(例如:玩家,敌人,小行星…),它们应该有不同的状态(例如:ok,传送…)

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

我该怎么做

更新1 更新2
您可以按如下方式声明接口:

public interface IHaveStatus {
    Status Status { get; set; }
}
并让特定类实现该接口:

class Player: IHaveStatus {
    public Status Status { get; set; }
}
这不会限制status字段的使用,它可以具有对
status
枚举合法的任何值

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

如果你想指定玩家有某些能力(例如:传送),你可以使用属性或接口来识别这些职业

使用接口:

public interface ICanTeleport { }

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

[Teleporter()]
public class Player { ... }
您可以使用cast确定能力:

if(somePlayer is ICanTeleport) { .. }
或使用时:

public interface ICanTeleport { }

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

[Teleporter()]
public class Player { ... }
然后必须使用反射来确定属性,请参见

  • 使用接口使行为绑定到类继承。它还使您能够向界面添加方法(即
    传送(坐标)
    方法)

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


您可以按如下方式声明接口:

public interface IHaveStatus {
    Status Status { get; set; }
}
并让特定类实现该接口:

class Player: IHaveStatus {
    public Status Status { get; set; }
}
这不会限制status字段的使用,它可以具有对
status
枚举合法的任何值

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

如果你想指定玩家有某些能力(例如:传送),你可以使用属性或接口来识别这些职业

使用接口:

public interface ICanTeleport { }

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

[Teleporter()]
public class Player { ... }
您可以使用cast确定能力:

if(somePlayer is ICanTeleport) { .. }
或使用时:

public interface ICanTeleport { }

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

[Teleporter()]
public class Player { ... }
然后必须使用反射来确定属性,请参见

  • 使用接口使行为绑定到类继承。它还使您能够向界面添加方法(即
    传送(坐标)
    方法)

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


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

       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;
                  }
              }
          }
      }
      

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

       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;
                  }
              }
          }
      }
      

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

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

      每个接受范围的解决方案枚举 类型级别的解决方案约束
      不能,至少不能使用相同的枚举类型。您必须为每一组允许的值声明不同的枚举。赞成:您可以进行编译时检查(只要像通常的枚举值那样显式分配值)。缺点:您必须为每个允许的范围声明一个新的枚举

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

      每个接受范围的解决方案枚举 类型级别的解决方案约束
      如果使用
      [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);
      

      如果使用
      [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);
      

      我不确定我是否会在接口上强制设置setter,但除此之外,回答得很好!:-)@ZoharPeled嘿,这只是一个财产。你想怎么做就怎么做-)只是我写评论时,我们的答案都是一样的,而不是那个细节…@oɔɯǝɹ感谢你的深入回答。因此,最终代码将是这样的:(参见更新的帖子:#Update1),实现IHaveStatus接口的类将只能使用
      public enum Status
      中公开的所有或部分值(在本例中:ok和teleporting),但不能添加新值?这是正确的吗?顺便说一句,在我们讨论的时候,我会回顾一下我的设计选择:)@oɔɯǝɹ为什么我不能写#Update2?我不确定我会在界面上强制设置一个setter,但除此之外,回答很好!:-)@ZoharPeled嘿,这只是一个财产。杜瓦