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