Указатель на словарь <> в c # - PullRequest
0 голосов
/ 24 марта 2011

У меня есть класс, его конструктор ниже

public GroupsForm(ref Dictionary<string, List<string>> groupsList)

Я хочу использовать groupsList и в других функциях, поэтому я объявил закрытый член в классе:

private Dictionary<string, List<string>> _groupsList;

Но проблема в том, что когда я делаю _groupsList = groupsList;, он делает копию groupsList, а изменения, сделанные в _groupsList, не меняют groupsList, так как я думаю, что по умолчанию это глубокая копия.Я хочу, чтобы он указывал на этот список.

В C ++ это легко сделать с помощью указателей, но кто-нибудь может сказать мне, как я могу сделать это в C #?


Ахмед опубликовал это изображение :

Debug session showing _groupsList.Count==3, whilst groupsList.Count==0

Ответы [ 5 ]

3 голосов
/ 24 марта 2011

Существуют типы значений и ссылочные типы в C # . Словарь является ссылочным типом, поэтому при назначении переменной, содержащей ссылочный тип, ссылка копируется, что означает, что обе переменные будут содержать одни и те же данные. Итак, если вы измените данные , вы должны ожидать, что они изменятся для обеих переменных:

List<int> list1 = new List<int>() { 1, 2, 3 };
List<int> list2 = list1;

list2.Add(10);
list1.ForEach(x => Console.WriteLine(x)); // should print 1, 2, 3 and 10.

Однако, если вы переназначаете переменную, то вы не меняете данные:

List<int> list1 = new List<int>() { 1, 2, 3 };
List<int> list2 = list1;

list2 = new List<int>() { 10, 11, 12 };
list1.ForEach(x => Console.WriteLine(x)); // should print 1, 2, 3 only

Одна вещь, которая привлекла мое внимание в вашем коде, это то, что конструктор ожидает ref. Это означает, что вы передаете ссылку непосредственно по ссылке, которая в C ++ будет выглядеть как двойной указатель (type**). Вы сделаете это, если в приведенном выше фрагменте вы хотите получить такой эффект:

void MethodA(ref List<int> list)
{
    list = new List<int>() { 10, 11, 12 };
}

// ...

List<int> list1 = new List<int>() { 1, 2, 3 };
MethodA(ref list1);
list1.ForEach(x => Console.WriteLine(x)); // should print 10, 11, 12

Еще одна вещь - AFAIK C # не реализует глубокие копии ни в одном из этих классов. Вы должны сделать это самостоятельно.

2 голосов
/ 24 марта 2011

В вашем методе InitGroups вы получили оператор присваивания _groupsList - это новый список, который содержит 3 элемента.Вы можете изменить InitGroups на что-то вроде:

var newGroups = (Dictionary<string, List<string>>)ser.ReadObject(reader,true);
foreach(var kvp in newGroups)
{
    _groupsList.Add(kvp.Key,kvp.Value);
}

И тогда вы все равно будете работать с тем же объектом Dictionary.

2 голосов
/ 24 марта 2011

Вам не нужно ref в подписи вашего метода. Все равно объекты передаются по ссылке.

И нет, копирование не происходит.

1 голос
/ 24 марта 2011

Но проблема в том, что я делаю _groupsList = groupsList; это делает копию groupsList

Нет, это не так. Копирует указатель Список является ссылочным типом.

, как мне кажется, по умолчанию он делает глубокую копию

Подумай еще раз. Ваш вывод неверен.

List<T> является ссылочным типом, поэтому все переменные являются указателями. Новичок C #, первая неделя, первый день, первый час. Вернитесь и прочитайте введение, а затем найдите ошибку в оставшейся части кода, которую вы нам не показываете.

0 голосов
/ 24 марта 2011

Вы ошибаетесь по нескольким пунктам.
Ссылки на C # полностью отличаются от C ++.

Короче, вы не должны использовать ref здесь, потому что это для распространения назначений, сделанных для параметра в вызывающий кодэто не то, что вы имеете в виду.

Вы ошибаетесь, предполагая, что здесь есть какое-либо копирование.
groupsList и _groups ist - это две ссылки, указывающие на один и тот же объект в памяти .

Вам нужно будет прочитать больше о ссылочных типах и типах значений в C # .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...