Использование структуры в качестве ключа для словаря и странные вещи происходят

Вот моя структура...

internal struct Coord : IEquatable<Coord>
{
    public int X { get; private set; }
    public int Y { get; private set; }

    public Coord(int x,int y) : this(){ X = x;
        Y = y;}

    //Overloaded operator functuions below
    //So I can easily multiply Coords by other Coords and ints and also add Coords together
    public static Coord operator *(Coord left, int right)
    {
        return new Coord(left.X * right, left.Y * right);
    }

    public static Coord operator *(Coord left, Coord right)
    {
        return new Coord(left.X * right.X, left.Y * right.Y);
    }

    public static Coord operator +(Coord left, Coord right)
    {
        return new Coord(left.X + right.X, left.Y + right.Y);
    }

    public static Coord operator -(Coord left, Coord right)
    {
        return new Coord(left.X - right.X, left.Y - right.Y);
    }


    public override int GetHashCode()
    {
        int hash = 17;
        hash = hash * 31 + X;
        hash = hash * 31 + Y;
        return hash;
    }

    public override bool Equals(object other)
    {
        return other is Coord ? Equals((Coord)other) : false;
    }

    public bool Equals(Coord other)
    {
        return X == other.X &&
               Y == other.Y;
    }
}

Я использую их как ключи для словаря, но я не думаю, что они приравниваются друг к другу должным образом. Значения в словаре являются объектами с полем bool. У меня есть цикл while, который делает с ними что-то и меняет bool на true, пока все они не становятся true. Он застревает в бесконечном цикле, так как они никогда не меняются на true. Что странно в том, что я не получаю ничего вне диапазона ошибки или что-то в этом роде, и когда я отлаживаю бит, где изменяется bool, кажется, что он работает нормально, но когда я смотрю на словарь в отладке, все bool все еще ложны

(примечание: я использовал Tuple в качестве ключа, но я создал эту структуру, чтобы можно было легко умножать и добавлять их)

Я просто хочу уточнить, что с тобой...

  _myDictionary = new Dictionary<Coord, RogueRoom>();
  _myDictionary[new Coord(4,5)] = new RogueRoom();
  _myDictionary[new Coord(4,5)].Connected = true

Те два раза, когда я получаю доступ к словарю, я получаю доступ к одному и тому же значению объекта?

РЕДАКТИРОВАТЬ: Вот структура значений в словаре (я заменил "вещь" выше)

internal struct RogueRoom
{
    public Room RoomField;
    public bool Connected;
    public Rectangle Realpos;
    public Color[] RogueRoomColors;
    public Coord Gridpos;
}

2 ответа

Решение

Это зависит от того, что Thing является. Если Thing это struct: нет; значение копируется при получении - хотя компилятор обычно останавливает назначение свойств для struct это собирается быть выброшенным. Если это classтогда это должен быть тот же экземпляр объекта; ваш равный / хэш-код выглядит разумно.

Ваше заявление _myDictionary[new Coord(4,5)].Connected = true; не должен компилироваться, так как методы и свойства, чей тип возврата является структурой (например, _myDictionary[new Coord(4,5)]) вернуть копии только для чтения этих типов структур, и вы пытаетесь записать в такую ​​структуру только для чтения.

Для краткости, я собираюсь сделать вид, что ваш словарь был Dictionary<int, RogueRoom>; дело в том, что Coordinate является определяемой пользователем структурой, здесь не имеет значения.

Если вы говорите var temp = _myDictionary[5]; это утверждение будет генерировать доступную для записи копию RogueRoom пример. Если вы говорите temp.Connected=true; это изменит эту копию, но оставит копию в словаре без изменений. Если вы хотите обновить файл, хранящийся в словаре, вам придется написать его обратно самостоятельно: _myDictionary[5] = temp;,

Если бы вы должны были изменить RogueRoom в изменчивый класс, то вы могли бы сказать, _myDictionary[5].Connected = true; изменить Connected свойство объекта, связанного с 5. Однако, к лучшему или к худшему, оно также изменило бы Connected свойство, связанное с любой другой ссылкой, которая существует на тот же объект. Например, если сказать _MyDictionary[2] = _MyDictionary[5];тогда утверждение _myDictionary[5].Connected = true; установит свойство connected объекта, связанного с 2 (поскольку объект, связанный с 2, является тем же объектом, что и связанный с 5).

Некоторым людям не нравятся изменчивые структуры, и они советуют вам разрабатывать свой тип так, чтобы код должен был что-то вроде:

var temp = _myDictionary[5];
_myDictionary[5] = new RogueRoom(temp.RoomField, true, temp.RealPos,
   temp.RogueRoomColors, temp.GridPos);

вместо того, чтобы просто обновить Connected собственностью temp и писать это обратно. Я считаю, что последний стиль излишне уродлив и неясен, но некоторые люди предпочитают его.

Что касается вопроса о том, должна ли вещь быть классом, это зависит от того, хотите ли вы каждое место хранения типа RogueRoom хранить пять независимых фрагментов информации, которые не зависят от тех, которые находятся в любом другом хранилище этого типа, или хотите ли вы разрешить нескольким хранилищам этого типа ссылаться на один и тот же экземпляр. Есть определенные варианты использования для обоих сценариев; вам нужно определить, что подходит именно вам.

Другие вопросы по тегам