С# - небезопасная замена значения словаря указателями

У меня есть два набора словарей, каждый из которых содержит одни и те же ключи и имеет инициализированные значения.

Используя небезопасный код, я хотел бы поменять их адреса местами:

Dictionary<string, List<object>> d1 = ...
Dictionary<string, List<object>> d2 = ...
unsafe void SwapEntries(string index)
{
    int* tmp = &d1[index];
    &d1[index] = &d2[index]
    &d2[index] = tmp;
}

Предполагая, что я правильно вспомнил свою арифметику указателя, результат, который я ищу, будет таким:

d1 = new Dictionary<string, List<int>>() { "a", { 1, 2, 3 } };
d2 = new Dictionary<string, List<int>>() { "a", { 4, 5, 6 } };
SwapEntries("a");
Console.WriteLine(d1["a"]); //4,5,6
Console.WriteLine(d2["a"]); //1,2,3

Однако, когда я пытаюсь написать это, я получаю ошибку компиляции «Невозможно взять адрес данного выражения».

1) Есть ли более быстрый способ выполнить обмен адресами, который я пропустил? Производительность является единственным приоритетом здесь.

2) Правильна ли моя арифметика указателя?

3) Нужно ли мне полностью переходить на оболочку или другую структуру данных, чтобы иметь возможность выполнять обмен адресами, как описано?


person Stardreamer    schedule 21.05.2017    source источник
comment
Зачем вам вообще нужна работа с указателями, почему бы просто не сделать SwapEntries(string index) { object tmp = d1[index]; d1[index] = d2[index]; d2[index] = tmp; } классы C# основанными на ссылках (вроде интеллектуальных указателей), здесь нет необходимости использовать указатели.   -  person Scott Chamberlain    schedule 22.05.2017
comment
Предложенный вами код вообще не имеет смысла. Вы используете int*, но int нигде не видно в этом фрагменте кода. У вас есть (что было бы на других языках) rvalue в левой части задания. И вещь, которую вы, кажется, хотите поменять местами, исходя из результата, уже ЯВЛЯЕТСЯ ссылочным типом, поэтому вам не нужно формировать указатель на нее, чтобы получить семантику дескриптора.   -  person Ben Voigt    schedule 22.05.2017


Ответы (2)


Я согласен с ответом Мартина Ульриха.

Выражение d1[index] не является переменной. Это вызов метода доступа get индексатора, определенного Dictionary<,>. Вы не можете взять указатель на это с помощью оператора &.

Кроме того, в данном случае это тип List<object>. Вы можете принимать указатели только на типы значений, а List<> — это тип class.

Даже если бы у вас было истинное место хранения, и оно было бы типа object[], это все равно было бы невозможно, так как тип элемента массива object. Таким образом, arr[0] (соответствующий d1[index][0]) снова будет типом class, и вы не можете взять его адрес.

Комментарий Скотта Чемберлена к вашему вопросу дает простой подход. Просто используйте

void SwapEntries(string index) 
{
    var tmp = d1[index];
    d1[index] = d2[index];
    d2[index] = tmp; 
}

Это просто включает в себя передачу ссылок на два существующих рассматриваемых экземпляра List<object>.

person Jeppe Stig Nielsen    schedule 21.05.2017
comment
Подумал, что вы не будете возражать против того, чтобы я возился с форматированием цитируемого кода :) - person Scott Chamberlain; 22.05.2017
comment
@ScottChamberlain Нет, конечно, все в порядке. Я исправил опечатку в вашем коде, так как object должно было быть List<object> (иначе как мы можем присвоить tmp обратно с помощью аксессора индексатора set?). Исправил с помощью var, на всякий случай. - person Jeppe Stig Nielsen; 22.05.2017

Автоматические указатели на элементы словаря не поддерживаются — они работают только для массивов или типов данных, которые используют функцию «возврат ссылки» C# 7 для индексаторов, свойств или методов.

person Martin Ullrich    schedule 21.05.2017