繁体   English   中英

强制一个类实现没有值约束的枚举

[英]Force a class to implement an enum with no value constrain

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

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

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

我怎样才能做到这一点?

UPDATE1

public enum Status
{
    Ok,
    Teleporting
};

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

更新2

public enum Status
{
    Ok,
    Teleporting
};

public interface IHaveStatus
{
    Status status;
}

您可以如下声明接口:

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

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

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

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

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

如果要指定播放器具有某些功能(例如,传送),则可以使用属性或接口来标识那些类别。

使用接口:

public interface ICanTeleport { }

public class Player : ICanTeleport { ... }

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

if(somePlayer is ICanTeleport) { .. }

或使用属性时

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

[Teleporter()]
public class Player { ... }

然后,您将必须使用反射来确定属性,请参阅此问题

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

  • 使用属性可以使更多的可能的对象即时混合和匹配功能,因为没有类别层次会强制这些功能。

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

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

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

或者,您可以在运行时在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;}
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM