C#Infinite While Loop使用ContainsValue和嵌套字典

时间:2015-01-19 03:30:00

标签: c# dictionary while-loop contains infinite

我在PHP中有这个脚本,我使用

  

while(in_array(array(' x' => $ x,' y' => $ y),$ worldMap)){...}

检查我的worldMap是否已在这些XY位置有空间。 如果为TRUE我随机选择X或Y,WHILE循环再次检查新值,依此类推,IF FALSE我填充生成最后一个XY的worldMap数组。

现在,我试图用C#重写代码,但我得到了一个无限循环。

这是我目前的代码:

public int nbRooms = 10;

private Dictionary<int, Dictionary<string, int>> worldMap = new Dictionary<int, Dictionary<string, int>>();
private Dictionary<string, int> roomXY = new Dictionary<string, int>();

private string[] arrayXY = {"X","Y"};
private int[] arrayNbr = {-1,1};
private int X = 0;
private int Y = 0;

    for(int i = 0; i <= nbRooms; i++)
    {
        while(worldMap.ContainsValue(roomXY))
        {
            string XorY = arrayXY[Random.Range(0, 2)];

            switch(XorY)
            {
            case "X": X += arrayNbr[Random.Range(0, 2)];
                break;
            case "Y": Y += arrayNbr[Random.Range(0, 2)];
                break;
            }

            roomXY.Clear();
            roomXY.Add("X", X);
            roomXY.Add("Y", Y);
        }

        worldMap.Add(i, roomXY);
    }

2 个答案:

答案 0 :(得分:0)

ContainsValue对 TValue 使用默认的相等比较器 EqualityComparer.Default ,这是字典中的值类型。 roomXY是一个(引用)字典对象,引用不会通过更改此对象的X和Y坐标进行更改,因此您将遇到无限循环。

答案 1 :(得分:0)

这里的基本问题是,默认情况下,两个引用类型对象之间的比较只是比较引用本身。当您更改roomXY对象的内容时,您不会更改引用本身(即实际对象保持不变),因此一旦您将对象添加到worldMap字典一次,它就会当您下次循环检查时,它总是在那里。

非常好地说明为什么在移植代码时移植 intent 非常重要,但不一定是确切的实现,因为语言处理的方式不同。

事实上,根据您发布的代码,在这种情况下,似乎您可能不想在任何地方使用字典类。可以使用字典对象使其工作,但您并没有真正利用这些数据结构的字典性质。看起来你在这里使用字典更多是因为在语义上它们看起来与你在PHP中使用的数据结构类似,但事实上C#提供了可能更合适的其他语言功能。

例如,您可以编写如下代码:

struct Room
{
    public readonly int X;
    public readonly int Y;

    public Room(int x, int y) { X = x; Y = y; }
}

public int nbRooms = 10;

private Room[] worldMap = new Room[nbRooms];

private string[] arrayXY = {"X","Y"};
private int[] arrayNbr = {-1,1};
private int X = 0;
private int Y = 0;
private Room roomXY = new Room(X, Y);

    for(int i = 0; i <= nbRooms; i++)
    {
        while(Array.IndexOf(worldMap, roomXY) >= 0)
        {
            string XorY = arrayXY[Random.Range(0, 2)];

            switch(XorY)
            {
            case "X": X += arrayNbr[Random.Range(0, 2)];
                break;
            case "Y": Y += arrayNbr[Random.Range(0, 2)];
                break;
            }

            roomXY = new Room(X, Y);    
        }

        worldMap[i] = roomXY;
    }

由于C#默认为值类型(即struct)实现了相等比较,这将比较roomXY值的实际内容与worldMap中的值进行比较

注意:您的原始实现和上面的实现都使用worldMap数据结构中的线性搜索。对于这里的少数房间(10),这应该没问题。但是你应该意识到,对于更大的数据集,这可能是非常低效的。在这种情况下,您可能希望使用不同的方法来生成此数据(例如,哈希集,较大的地图数据结构中的标记,重排等)。