Подтвердить что ты не робот

Почему возможно создать структуру без нового ключевого слова?

Почему мы не вынуждены создавать экземпляр структуры, например, при использовании класса?

4b9b3361

Ответ 1

Почему просто - , потому что спецификация говорит. Как нужно обеспечить, чтобы весь блок памяти был "определенно назначен", а это означает: присвоение значения каждому полю структуры. Однако это требует 2 неприятных вещей:

  • публичные поля (почти всегда плохие)
  • изменяемые поля (как правило, плохо в структуре)

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

Ответ 2

Почему мы не вынуждены создавать структуру с помощью "new", например, при использовании класса?

Когда вы "новый" ссылочный тип, происходят три вещи. Во-первых, диспетчер памяти выделяет пространство из хранилища долгосрочного. Во-вторых, ссылка на это пространство передается конструктору, который инициализирует экземпляр. В-третьих, эта ссылка передается обратно вызывающему абоненту.

Когда вы "новый" тип значения, происходят три вещи. Во-первых, диспетчер памяти выделяет пространство из краткосрочного хранилища. Во-вторых, конструктор получает ссылку на кратковременное хранилище. После запуска конструктора значение, которое находилось в кратковременном хранилище, копируется в хранилище для значения, где бы это ни было. Помните, что переменные типа значения сохраняют фактическое значение.

(Обратите внимание, что компилятору разрешено оптимизировать эти три шага на один шаг, если компилятор может определить, что это никогда не предоставляет частично построенный код структуры для пользователя. То есть компилятор может сгенерировать код, который просто передает ссылку в конечное место хранения для конструктора, тем самым сохраняя одно выделение и одну копию.)

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

Почему мы вынуждены выделять класс с "новым" вместо того, чтобы просто инициализировать поля как со структурой?

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

Вам не нужно вызывать "новое" в структуре, потому что нет необходимости выделять "окончательное" хранилище; окончательное хранилище уже существует. Новое значение будет идти куда-то, и вы уже получили это хранилище другими способами. Типы значений не нуждаются в новом распределении; все, что им нужно, это инициализация. Все, что вам нужно сделать, это убедиться, что хранилище правильно инициализировано, и вы часто можете это сделать без вызова конструктора. Конечно, это означает, что вы рискуете иметь переменную типа значения, которая может наблюдаться в частично инициализированном состоянии по коду пользователя.

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

Ответ 3

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

Поэтому конструктор (оператор new) является необязательным для структуры.

Рассматривать

struct V { public int x; }
class  R { public int y = 0; }

void F() 
{
   V a;   // a is an instance of V, a.x is unassigned  
   R b;   // b is a reference to an R

   a.x = 1; // OK, the instance exists
 //b.y = 2; // error, there is no instance yet

   a = new V();  // overwrites the memory of 'a'. a.x == 0
   b = new R();  // allocates new memory on the Heap

   b.y = 2; // now this is OK, b points to an instance
}

Ответ 4

Потому что структуры - это типы значений, а классы - ссылочные типы. Таким образом, структуры относятся к той же категории, что и int, double и т.д.

Ответ 5

Через полтора года...

struct обычно передается по значению, а class всегда передается по ссылке. Вы, вероятно, хорошо понимаете, что происходит, когда объект передается по ссылке. Когда объект передается по значению, его содержимое, а не ссылка на объект, передается. Программисту кажется, что сделана мелкая копия объекта. Изменение одного экземпляра не изменит другого.

Всем переменным (включая поля и свойства) всегда выделяется пространство для них, пока они существуют. Важно отметить, что локальные переменные не существуют, пока им не будет присвоено значение в более новых версиях С#. В случае переменных class -type выделенное пространство будет содержать ссылку на содержимое объекта. В случае переменной struct -type выделенное пространство будет содержать фактическое содержимое объекта.

Итак, допустим, у вас есть "пустая" переменная class -type. Он будет иметь ссылку по умолчанию. Эта ссылка будет равна null. Однако переменная struct -type не является ссылкой: это фактическое содержимое объекта. Когда оставлено "пустым", все его поля (и автоматически реализуемые свойства, которые подкреплены полями за кулисами) все содержат значения по умолчанию - другими словами, они также "пустые". Если они являются ссылочными типами, они будут null; если они являются типами значений, они будут равны 0 или обнуляются структуры (и цепочка продолжается).

По этой же причине structs не могут иметь конструктор по умолчанию. Точно так же, как вы не можете переопределить то, как выглядит class когда он null, вы не можете переопределить то, как выглядит struct когда он обнуляется.

Существует недостаточно используемый оператор для получения значения по умолчанию любого class type--, struct или встроенного. Это оператор по default(). Например:

class ClassType { }
struct StructType { }

//
// ...
//

var classA = default(ClassType);
var classB = (ClassType)null;

if (classA == classB)
{
    // This will execute, because both equal null.
}

var structA = default(StructType);
var structB = new StructType();

if (structA == structB)
{
    // This will execute, because both are zeroed.
}

//
// ...
//

/// <summary>
/// An example use case for the <c>default()</c> operator.
/// </summary>
/// <returns>
/// <c>null</c> if <c>T</c> is a reference type, a zeroed instance <c>T</c> is a 
/// <c>struct</c>, or <c>0</c> if <c>T</c> is an intrinsic type.
/// </returns>
private static T GetDefault<T>()
{
    // This line wouldn't compile, because T could be a value type.
    //return null;

    // This line wouldn't compile, because T could be a reference type without a default or accessible constructor.
    //return new T();

    // This will work!
    return default(T);

    // In newer versions of C#, when the type is known from the context, it can be omitted:
    //return default;
}

Ответ 6

Как сказано Дэвидом Хеффернаном и Хенком Холтерманом, потому что структуры являются типами значений и, следовательно, создаются при объявлении. Для лучшего понимания ValueType и ReferenceType, пожалуйста, проверьте эту ссылку P Daddy. Это объяснимо.

Ответ 7

Кроме того, что было опубликовано: обратите внимание, что структура не может иметь конструктор без параметров или иметь инициализатор для любого из его полей экземпляра. Значение по умолчанию имеет все поля типа значения, установленные для их значения по умолчанию (например, для int, false для bool и т.д.), А все поля ссылочного типа - null.

Во-вторых, инициализируется структура, например, путем вызова конструктора или использования default().