Что не так с этой структурой C #? - PullRequest
3 голосов
/ 16 марта 2012

Примечание: мой вопрос состоит из нескольких частей. Буду признателен, если вы ответите на каждый из вопросов, а не просто скажете мне, что нужно сделать, чтобы это скомпилировать. :)

Я не очень хорош в C #. Фактически, причина, по которой я мало что знаю об этом, заключается в том, что мой класс сосредоточен на создании эффективных алгоритмов, а не на обучении нас .NET. Тем не менее, все наши программы должны быть написаны на .NET, и это не было проблемой до сих пор. У меня есть следующий код, но он не скомпилируется, и я не совсем понимаю, почему. У меня есть ощущение, что это должно быть полностью переписано, но прежде чем я это сделаю, я хочу знать, ПОЧЕМУ это не разрешено.

Смысл структуры состоит в том, чтобы создать связанный список, подобный структуре, чтобы я мог добавить еще один узел в конец «списка», а затем пройти и вызвать узлы в обратном порядке

private struct BackPointer
{
    public BackPointer previous;
    public string a;
    public string b;
    public BackPointer(BackPointer p, string aa, string bb)
    {
        previous = p;
        a = aa;
        b = bb;
    }
}

потом в моем коде я что-то с эффектом

BackPointer pointer = new BackPointer();
pointer = new BackPointer(pointer, somestring_a, somestring_b);

Я получаю ошибку компиляции Struct member 'MyClass.BackPointer.previous' of type 'MyClass.BackPointer' causes a cycle in the struct layout

Кажется, это очевидная ошибка. Не нравится тот факт, что я передаю структуру в конструкторе той же структуры. Но почему это не разрешено? Я предположил бы, что этот код просто создаст новый узел в списке и вернет этот узел с указателем на предыдущий узел, но, очевидно, это не то, что произойдет. Так что же тогда будет на самом деле? Наконец, каков рекомендуемый способ решить эту проблему? Я думал просто сказать, что это неуправляемо, просто обрабатывать мои указатели вручную, но я действительно знаю, как это сделать в C ++. Я действительно не знаю, что может пойти не так в C #

Ответы [ 5 ]

10 голосов
/ 16 марта 2012

Это не указатель;это фактическое встроенное struct значение.
Смысл struct s в том, что они (почти) никогда не указатели.

Вместо этого следует использовать class.

6 голосов
/ 16 марта 2012

Но почему это не разрешено?

Это структура - тип значения. Это означает, что где бы у вас ни была переменная этого типа, эта переменная содержит все поля внутри структуры, непосредственно встроенные. Если что-то содержит себя (или создает более сложный цикл), то вы явно не можете выделить для него достаточно места - потому что у него должно быть достаточно места для всех его полей и другой копии самого себя .

И, наконец, каков рекомендуемый способ решения этой проблемы?

Напишите класс вместо структуры. Тогда значение переменной будет ссылкой на экземпляр, а не на сами данные. Вот как вы получаете близко к «указателю» в C #. (Указатели и ссылки разные, заметьте.)

Я предлагаю вам прочитать мою статью о типах значений и ссылочных типах для получения дополнительной информации - это абсолютно критическая тема для понимания в C #.

3 голосов
/ 16 марта 2012

Backpointer ДОЛЖЕН существовать до создания Backpointer, потому что у вас не может быть Backpointer без другого Backpointer (для которого затем потребуется еще один Backpointer и так далее). Вы просто не можете создать Backpointer на основе способа, которым вы его создали, потому что, как структура, Backpointer никогда не может быть нулевым.

Другими словами, невозможно создать Backpointer с этим кодом. Компилятор знает это, и поэтому он заставляет вас делать что-то, что будет работать логически.

0 голосов
/ 16 марта 2012

A CLR struct по определению является типом значения .В вашем контексте это означает, что компилятор должен знать точную компоновку типа.Тем не менее, он не может знать, как расположить тип, который содержит экземпляр самого себя - это звучит разумно?Измените структуру на класс (что делает ваш BackPointer ссылочным типом ), и вы увидите, что он будет работать из коробки.Причина в том, что экземпляр любого ссылочного типа всегда имеет одну и ту же компоновку - это в основном просто «указатель» на какое-то место управляемой кучи.Я настоятельно рекомендую прочитать немного об основах системы типов C # или CLI.

0 голосов
/ 16 марта 2012

Структуры хранятся по значению. В этом случае ваша структура хранит в себе другой экземпляр той же структуры. Эта структура хранит в себе другую структуру и так далее. Поэтому это невозможно. Это все равно что сказать, что у каждого человека в мире должен быть 1 ребенок. Нет никакого способа, которым это возможно.

То, что вам нужно использовать, это класс. Классы хранятся по ссылке, что означает, что он не хранит класс внутри себя, он только сохраняет ссылку на этот класс.

...