Структуры .NET копируются при записи? - PullRequest
3 голосов
/ 08 января 2011

.NET-структуры являются типами значений, это означает, что если функция A создает структуру и вызывает функцию B, которая пытается изменить структуру, B получит новую копию структуры, поэтому изменения не будут применяться к структуре A.

Структуры могут быть намного больше, чем другие типы значений CLR.Допустим, одна функция создает большую структуру, вызывает другую и передает структуру функции.Это продолжается для 10 уровней, но все функции просто должны читать данные из структуры и не изменять ни одно из полей.Если новая копия структуры действительно создается при каждом вызове функции, приведенный выше сценарий приведет к выделению множества ненужных структур.

Пользователи языка C могут избежать этого, передав указатель вместо самой структуры, и есливнутренние функции не должны изменять эти данные в структуре, можно использовать ключевое слово const.

Однако в C # вместо указателей есть ссылки, и такой вещи, как const ref, не существует.

Мой вопрос: оптимизирован ли .NET таким образом, что он знает, что нужно копировать структуру только тогда, когда функция пытается изменить поля внутри, или эта новая копия всегда создается, когда структура передается другой функции?

Ответы [ 4 ]

4 голосов
/ 08 января 2011

приведенный выше сценарий приведет к выделению множества ненужных структур

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

В остальном это работает почти идентично, как в собственном коде C / C ++, с оговоркой, что JIT-компилятор x86имеет тенденцию генерировать лучший код, поскольку передача структуры всегда проходит через стек в собственных соглашениях о вызовах (кроме __fastcall).Также поддерживаются указатели, как и в C, вы просто объявляете аргумент с ключевым словом ref .Без ключевого слова const вам придется жить без этого.

Стоимость прохождения структур резко возрастает, когда структура больше 16 байт.Он больше не помещается в стек, джиттер генерирует код для передачи указателя на копию значения в локальном кадре стека.В результате значение копируется дважды, как на месте вызова, так и на вызываемого абонента.Вот почему .NET Framework Guide рекомендует переключаться на класс, когда структура становится слишком большой.Однако передача по ссылке работает также, чтобы избежать копирования, с оговоркой, что доступ всех членов является косвенным.Как и в C.

Не стесняйтесь использовать класс вместо struct, сборщик мусора очень эффективен.

1 голос
/ 08 января 2011

Вы можете передать тип значения по ссылке:

public void SomeMethod(ref SomeValueType someValue)

Но чтобы ответить на ваш конкретный вопрос, нет, я не верю, что есть такие оптимизации, и я не считаю их желательными. Я бы предпочел иметь последовательное поведение. Если вы используете массивные типы значений и раздает их по воле случая, вы делаете это неправильно.

0 голосов
/ 08 января 2011

ответить на вопрос;структуры yes копируются всякий раз, когда необходимо: запись в поле / переменную или передача в метод.Это не оптимизировано далеко и не должно быть

1002 * Если это структура, она должна быть неизменна - тогда вопрос о другом методе меняющегося поля спорен:. оно не должно быть изменением ихи они должны быть только для чтения .

По вопросу о чрезмерном размере;если он слишком большой, он не должен быть структурой;это должен быть класс - но если он представляет собой дискретное значение, вы также можете оставить его неизменным даже в форме класса.

Другой ответ на обе проблемы - передать его «ref» в методы или инкапсулироватьэто как поле, а не свойство в классе, но IMO, как правило, означает, что они в первую очередь неправильно используют структуру.

Реальное изменение, которое я хотел бы сделать здесь, заключается воценить, действительно ли это является"значением".Ценности никогда не меняются;поэтому структуры не должны мутировать.Если вы не можете сказать это о своем типе, вероятно, это не должна быть структура.

0 голосов
/ 08 января 2011

Если ваша структура содержит свойства, в отличие от полей, вы можете объявить интерфейс readonly со структурой и вместо этого передать ссылку на него.

public interface IMyReadOnlyStruct
{
   int A { get; }
}

public struct MyStruct: IMyReadOnlyStruct
{
   public int A { get; set; }
}

public void MyReadOnlyMethod(ref IMyReadOnlyStruct a)
{
    ....
}

Это также, как я бы передавал readonlyссылка на объект вокруг.Поскольку вы можете сделать это, C # не должен поддерживать const.Используя интерфейсы, вы можете иметь как константную ссылку, так и ссылку, где доступен только любой заданный поднабор свойств объектов.

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

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