C#-使用泛型枚举(或用于控制列表的替代方法)
本文关键字:列表 方法 控制 用于 泛型 枚举 C#- | 更新日期: 2023-09-27 18:21:54
我正在为游戏编写一个寻路算法,但试图保持它的通用性,以便在未来的应用程序中使用。
我有一个Node类,它包含X、Y和"PassableType"。
NodeGrid类存储一个节点数组,包含它们如何连接的图形信息,然后有一个FindAStarPath()函数,该函数的参数为StartNode、EndNode和"PassableTypes"的params。
我的问题是确定"PassableType"应该具有什么类型。
理想情况下,我想要的是能够使用通用枚举,即每个游戏定义的限制列表。节点将持有该列表中的单个元素,以说明它是什么路径类型(当前游戏可能使用路径、草地、墙等)
因此,当一个实体尝试路径时,它提供了路径查找功能,将其类型视为"可通过"。所以一个人可能会使用
FindAStarPath(CurrentNode, DestinationNode, "Path", "Floor", "Door");
但是汽车可能只使用
FindAStarPath(StartNode, EndNode, "Road");
我的问题是,我不知道如何让NodeGrid采用Generic枚举或等效逻辑。
目前我有字符串,但这意味着我必须写
MyEnum.Road.ToString()每次我使用它。
理想情况下,我想做一些类似的事情
NodeGrid<MyEnum> CurrentNodeGrid = new NodeGrid<MyEnum>()
然后,节点将使用MyEnum作为其passableType,路径查找功能也是如此,从而允许每个游戏都有一组不同的瓦片类型用于路径查找。
但我不能将NodeGrid定义为:
public class NodeGrid<T> where T:enum
为了清楚起见,使用此枚举的寻路函数的唯一部分是(包含在Node中):
public bool IsPassable(string[] passableTypes)
{
for (var i = 0; i < passableTypes.Count(); i++)
{
if (this.PassableType == passableTypes[i]) return true;
}
return false;
}
谢谢Haighstrom
除非您使用枚举的某些特定功能(如Enum.Parse
),否则我看不出有任何理由将其限制在它们之上。通过释放约束,调用方可以使用他们认为合适的任何类型,如enum
、一组string
值(如您当前所拥有的)或一组要检查的自定义类实例。
public class NodeGrid<T>
{
public T PassableType { get; private set; }
public bool IsPassable(params T[] passableTypes)
{
return IsPassable((IEnumerable<T>)passableTypes);
}
public bool IsPassable(IEnumerable<T> passableTypes)
{
foreach(T passType in passableTypes)
{
if (EqualityComparer<T>.Default.Equals(this.PassableType, passType))
return true;
}
return false;
}
}
但是由于我们现在使用泛型,您不能再使用==
比较了。最简单的方法是利用EqualityComparer.Default实用程序。在直接调用this.PassableType.Equals(passType)
时使用它的主要原因是,它将执行null检查,并在适用的情况下正确利用泛型,如果类型实现IEquatable<T>
,则使用这些泛型版本。可能还有其他一些小事。它通常最终会调用Object.Equals
过载。
基于你的问题的一些例子:
//using a custom enum, calls the params T[] overload
NodeGrid<MyCarEnum> carNode = ...
carNode.IsPassable(MyCarEnum.Road, MyCarEnum.Tunnel);
//demonstrates receiving a set of pass types strings from an external source
List<string> passTypes = new List<string>("Path", "Floor", "Door");
NodeGrid<string> personNode = ...
personNode.IsPassable(passTypes) //calls the IEnumerable<T> overload
//feel free to declare enums wherever you want,
//it can avoid potential mixups like this:
NodeGrid<string> airplaneNode = ...
NodeGrid<string> personNode = ...
NodeGrid<MyCarEnum> carNode = ...
airplaneNode.IsPassable("Floor"); //makes no sense, but will compile
personNode.IsPassable("Clouds"); //makes no sense, but will compile
carNode.IsPassable("Sky"); //compile error: was expected a MyCarEnum value