Здравствуйте.
Имеется коллекция _data (Dictionary), где ключем выступает массив типа int[], а значением является условный тип.
private static Dictionary<int[], SomeType> _data = new Dictionary<int[], SomeType>();
Я добавил в коллекцию какие то данные, например так:
_data.Add(new int[2] { 1, 2 }, new SomeType(p1, p2));
Но при получении значений возникла проблема, если написать:
_data.ContainsKey(new int[2] { 1, 2 });
То всегда будет false. Я так понял потому что инициализирую все время новый массив, а не даю ссылку на него. Сам вопрос заключается в том, как лучше и проще всего в данном случае оперировать с набором данных как ключем. Я только изучаю этот прекрасный язык, недавно почитав о структурах, понял что может быть их лучше использовать в данном случае, но все таки хотел узнать у опытных программистов.
Вы правы, получить данные не удается, потому что ваш ключ ссылочного типа, и вы всегда создаете новый объект, вместо того чтобы использовать ссылку на оригинальный.
В тех случаях, когда вы нигде не храните ссылки на оригинальные объекты, удобнее использовать в качестве ключей значимые типы или строки. Например - вот так:
private string GetKey(params int[] values) {
return string.Join("_", values);
}
_data.Add(GetKey(1, 2), new SomeType(p1, p2));
В таком случае вы в любое сможете получить ключ, нигде не храня его.
Использовать ссылки на объекты в качестве ключей удобно только тогда, когда эти объекты у вас где-то еще "работают", и время от времени возникает необходимость получить информацию, имея на руках ссылку на такой объект. Судя по коду, ваша программа устроена не так.
Дело в том, что Dictionary<TKey, TValue>
использует GetHashCode
. Класс Array
не переопределяет этот метод, а значит используется реализация класса System.Object
. Под капотом вызывается нативный метод CLR
ObjectNative::GetHashCode
, который делает что-то, чего никто не знает. Но факт в том, что одинаковые объекты имеют разный хеш код, если они находятся по разным адресам. Вот пример:
int[] x1 = new[] { 1, 2 };
int[] x2 = new[] { 1, 2 };
Console.WriteLine(x1.GetHashCode());
Console.WriteLine(x2.GetHashCode());
Выводит:
46104728
12289376
Dictionary<TKey, TValue>
в первую очередь сравнивает хеш-коды, а потом уже пытается сравнить объекты.
Для вашей задачи нужно создать класс, который будет содержать внутри себя массив, переопределить в нем GetHashCode
и метод Equals
. А еще лучше реализовать интерфейс IEquatable. Как правильно реализовать GetHashCode
- отдельный вопрос. Можно например "скопипастить" GetHashCode
из класса System.String
, который уж точно реализован отлично:
class MyArray : IEquatable<MyArray>
{
private int[] _array;
public MyArray(int[] array)
{
this._array = array;
}
public override int GetHashCode()
{
int num = 5381;
int num2 = num;
for (int i = 0; i < _array.Length; i += 2)
{
num = ((num << 5) + num ^ _array[i]);
if (i + 1 == _array.Length)
break;
num2 = ((num2 << 5) + num2 ^ _array[i + 1]);
}
return num + num2 * 1566083941;
}
// Equals и др.
}
Теперь вам вместо ключа int[]
нужно использовать экземпляры MyArray
.
int[] x1 = new[] { 1, 2 };
int[] x2 = new[] { 1, 2 };
var a1 = new MyArray(x1);
var a2 = new MyArray(x2);
Console.WriteLine(a1.GetHashCode());
Console.WriteLine(a2.GetHashCode());
Такой код теперь покажет одинаковые хеш-коды:
-1776415353
-1776415353
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Ищу способ сменить выходную ноду тора программно из c#Ну и было бы здорово узнать как указать определенные страны выходной ноды программно,...
Есть div, который намного больше размера окнаИщу такую библиотеку или способ, чтобы по этому элементу можно было перемещаться как в гугл картах...