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

C#-使用泛型枚举(或用于控制列表的替代方法)

除非您使用枚举的某些特定功能(如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