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

Hai*_*rom 3 c# generics enums

我正在为游戏编写一个寻路算法,但试图保持它的通用性,以便它可以在未来的应用程序中使用.

我有一个Node类,它包含X,Y和"PassableType".

NodeGrid类存储一个节点数组,包含它们如何连接的图形信息,然后有一个FindAStarPath()函数,该函数将"PassableTypes"作为参数StartNode,EndNode和params.

我的问题是确定"PassableType"应该具有什么类型.

理想情况下我想要的是能够使用通用枚举 - 即每个游戏定义的限制列表.Node将保存该列表中的单个元素,以说明它是什么路径类型(当前游戏可能使用Path,Grass,Wall等)

因此,当实体尝试路径时,它提供路径查找功能,其类型被视为"可通过".所以男人可以使用

FindAStarPath(CurrentNode, DestinationNode, "Path", "Floor", "Door");
Run Code Online (Sandbox Code Playgroud)

但是汽车可能会使用

FindAStarPath(StartNode, EndNode, "Road");
Run Code Online (Sandbox Code Playgroud)

我的问题是我无法弄清楚如何让NodeGrid采用Generic枚举或等效逻辑.

目前我已经接受了字符串,但这意味着我
每次使用它时都必须编写MyEnum.Road.ToString().

理想情况下,我想做点什么

NodeGrid<MyEnum> CurrentNodeGrid = new NodeGrid<MyEnum>()
Run Code Online (Sandbox Code Playgroud)

然后Nodes会将MyEnum作为passableType,路径寻找函数也是如此,因此每个游戏都有一组不同的tile类型用于路径.

但我不能将NodeGrid定义为:

public class NodeGrid<T> where T:enum
Run Code Online (Sandbox Code Playgroud)

为清楚起见,使用此枚举的唯一部分路径查找功能是这个(包含在Node中):

    public bool IsPassable(string[] passableTypes)
    {
        for (var i = 0; i < passableTypes.Count(); i++)
        {
            if (this.PassableType == passableTypes[i]) return true;
        }
        return false;
    }
Run Code Online (Sandbox Code Playgroud)

谢谢Haighstrom

Chr*_*air 5

除非你使用枚举的某些特定功能(比如Enum.Parse),否则我没有任何理由将它限制在它们之内.通过释放约束,调用者可以使用他们认为合适的任何类型,beit 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但由于我们现在使用泛型,你不能再使用==比较了.最简单的方法是利用EqualityComparer.Default实用程序.使用它直接调用的主要原因this.PassableType.Equals(passType)是它将执行空检查并在适用的情况下正确利用泛型,如果类型实现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
Run Code Online (Sandbox Code Playgroud)