Что делает ключевое слово " new " для структуры в C#?
в C# структуры управляются в терминах значений, а объекты-в ссылках. Насколько я понимаю, при создании экземпляра класса ключевое слово new
заставляет C# использовать информацию о классе для создания экземпляра, как показано ниже:
class MyClass
{
...
}
MyClass mc = new MyClass();
для struct вы не создаете объект, а просто устанавливаете переменную в значение:
struct MyStruct
{
public string name;
}
MyStruct ms;
//MyStruct ms = new MyStruct();
ms.name = "donkey";
то, что я не понимаю, если объявить переменные с помощью MyStruct ms = new MyStruct()
, что такое ключевое слово new
здесь делаете заявление? . Если struct не может быть объектом, то что такое new
здесь инстанцирования?
6 ответов:
С
struct (C# Reference)
на MSDN:при создании объекта структуры с помощью оператора new, он создается и вызывается соответствующий конструктор. В отличие от классов, структуры могут быть созданы без использования оператора new. Если вы не используете new, поля останутся неназначенными, и объект нельзя будет использовать до тех пор, пока все поля не будут инициализированы.
насколько я понимаю, вы на самом деле не сможете правильно использовать структуру без использования новая если вы не убедитесь, что инициализируете все поля вручную. Если вы используете оператор new, конструктор сделает это за вас.
надеюсь, что это проясняет. Если вам нужны разъяснения по этому поводу, дайте мне знать.
Edit
там довольно длинный поток комментариев, поэтому я подумал, что добавлю немного больше здесь. Я думаю, что лучший способ понять это, чтобы дать ему идти. Создание консольного проекта в Visual Studio вызывается "StructTest" и копирует в него следующий код.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace struct_test { class Program { public struct Point { public int x, y; public Point(int x) { this.x = x; this.y = 5; } public Point(int x, int y) { this.x = x; this.y = y; } // It will break with this constructor. If uncommenting this one // comment out the other one with only one integer, otherwise it // will fail because you are overloading with duplicate parameter // types, rather than what I'm trying to demonstrate. /*public Point(int y) { this.y = y; }*/ } static void Main(string[] args) { // Declare an object: Point myPoint; //Point myPoint = new Point(10, 20); //Point myPoint = new Point(15); //Point myPoint = new Point(); // Initialize: // Try not using any constructor but comment out one of these // and see what happens. (It should fail when you compile it) myPoint.x = 10; myPoint.y = 20; // Display results: Console.WriteLine("My Point:"); Console.WriteLine("x = {0}, y = {1}", myPoint.x, myPoint.y); Console.ReadKey(true); } } }
поиграйте с ним. Удалите конструкторы и посмотрите, что произойдет. Попробуйте использовать конструктор, который инициализирует только одну переменную(я прокомментировал один из них... он не будет компилироваться). Попробуйте С и без новая ключевое слово (я прокомментировал некоторые примеры, раскомментируйте их и дайте им попробовать).
Лови отличный ответ Эрика Липперта из этой темы. процитирую его:
когда вы "новый" тип значения, происходят три вещи. Во-первых, память менеджер выделяет место из краткосрочного хранилища. Во-вторых, конструктору передается ссылка на место краткосрочного хранения. После запуска конструктора значение, которое было в краткосрочной перспективе место хранения копируется в место хранения для значения, где бы это ни случилось. Помните, что переменные типа значения хранят фактическое значение.
(обратите внимание, что компилятор может оптимизировать эти три шага в один шаг, если компилятор может определить, что это никогда не предоставляет частично построенная структура для пользовательского кода. То есть, компилятор может создайте код, который просто передает ссылку на конечное хранилище расположение к конструктору, тем самым сохраняя одно распределение и одно копировать.)
(что делает этот ответ так как это действительно один)
использование "new MyStuct ()" гарантирует, что все поля имеют некоторое значение. В приведенном выше случае, ничего не изменилось. Если вместо установки ms.name вы, где пытаетесь прочитать его, вы получите ошибку" использование возможного неназначенного поля " имя "" в VS.
каждый раз, когда объект или структура появляется, все его поля также появляются; если любое из этих полей является типом структуры, все вложенные поля также появляются. Когда массив создается, все его элементы возникают (и, как указано выше, если какой-либо из этих элементов является структурой, поля этих структур также возникают). Все это происходит до того, как любой код конструктора имеет шанс запустить.
в .net конструктором структуры является фактически не более чем метод, который принимает структуру в качестве параметра "out". В C# выражение, которое вызывает конструктор структуры, выделит временный экземпляр структуры, вызовет конструктор на нем, а затем использует этот временный экземпляр в качестве значения выражения. Обратите внимание, что это отличается от vb.net, где сгенерированный код для конструктора будет начинаться с обнуления всех полей, но где код от вызывающего объекта будет пытаться заставить конструктор работать непосредственно на назначение. Например:
myStruct = new myStructType(whatever)
in vb.net будет ясноmyStruct
перед первым оператором конструктора выполняется; в конструкторе любая запись в строящийся объект будет немедленно работать наmyStruct
.
ValueType
и структуры-это что-то особенное в C#. Здесь я показываю вам, что происходит, когда вы новая что-то.здесь мы имеем следующее
код
partial class TestClass { public static void NewLong() { var i=new long(); } public static void NewMyLong() { var i=new MyLong(); } public static void NewMyLongWithValue() { var i=new MyLong(1234); } public static void NewThatLong() { var i=new ThatLong(); } } [StructLayout(LayoutKind.Sequential)] public partial struct MyLong { const int bits=8*sizeof(int); public static implicit operator int(MyLong x) { return (int)x.m_Low; } public static implicit operator long(MyLong x) { long y=x.m_Hi; return (y<<bits)|x.m_Low; } public static implicit operator MyLong(long x) { var y=default(MyLong); y.m_Low=(uint)x; y.m_Hi=(int)(x>>bits); return y; } public MyLong(long x) { this=x; } uint m_Low; int m_Hi; } public partial class ThatLong { const int bits=8*sizeof(int); public static implicit operator int(ThatLong x) { return (int)x.m_Low; } public static implicit operator long(ThatLong x) { long y=x.m_Hi; return (y<<bits)|x.m_Low; } public static implicit operator ThatLong(long x) { return new ThatLong(x); } public ThatLong(long x) { this.m_Low=(uint)x; this.m_Hi=(int)(x>>bits); } public ThatLong() { int i=0; var b=i is ValueType; } uint m_Low; int m_Hi; }
и сгенерированный IL методов тестового класса будет
IL
// NewLong .method public hidebysig static void NewLong () cil managed { .maxstack 1 .locals init ( [0] int64 i ) IL_0000: nop IL_0001: ldc.i4.0 // push 0 as int IL_0002: conv.i8 // convert the pushed value to long IL_0003: stloc.0 // pop it to the first local variable, that is, i IL_0004: ret } // NewMyLong .method public hidebysig static void NewMyLong () cil managed { .maxstack 1 .locals init ( [0] valuetype MyLong i ) IL_0000: nop IL_0001: ldloca.s i // push address of i IL_0003: initobj MyLong // pop address of i and initialze as MyLong IL_0009: ret } // NewMyLongWithValue .method public hidebysig static void NewMyLongWithValue () cil managed { .maxstack 2 .locals init ( [0] valuetype MyLong i ) IL_0000: nop IL_0001: ldloca.s i // push address of i IL_0003: ldc.i4 1234 // push 1234 as int IL_0008: conv.i8 // convert the pushed value to long // call the constructor IL_0009: call instance void MyLong::.ctor(int64) IL_000e: nop IL_000f: ret } // NewThatLong .method public hidebysig static void NewThatLong () cil managed { // Method begins at RVA 0x33c8 // Code size 8 (0x8) .maxstack 1 .locals init ( [0] class ThatLong i ) IL_0000: nop // new by calling the constructor and push it's reference IL_0001: newobj instance void ThatLong::.ctor() // pop it to the first local variable, that is, i IL_0006: stloc.0 IL_0007: ret }
поведение методов прокомментировано в коде IL. И возможно, вы захотите взглянуть на Коды операций.Initobj и опкоды.Newobj. Тип значения обычно инициализируется с помощью Коды операций.Initobj, но как говорит MSDN опкоды.Newobj также будет использоваться.
описание опкоды.Newobj
типы значений обычно создано с помощью newobj. Они обычно выделяются либо как аргументы, либо как локальные переменные, использующие newarr (для одномерных массивов на основе нуля) или как поля объектов. После выделения они инициализируются с помощью Initobj. , инструкция newobj может быть использована для создания нового экземпляра типа значения в стеке, который затем может быть передан в качестве аргумента, сохраненного в локальном и так далее.
для каждого типа значения, который является числовым, от
byte
доdouble
, имеет определенный op-код. Хотя они объявлены какstruct
, есть некоторая разница в сгенерированном IL, как показано на рисунке.вот еще две вещи, чтобы отметить:
объявлен абстрактный класс
то есть, вы не можете новая это напрямую.
struct
s не может содержать явных конструкторов без параметровто есть, когда вы новая a
struct
, вы бы попали в дело выше любогоNewMyLong
илиNewMyLongWithValue
.подведем итоги,новая для типов значений и структур предназначены для согласованности концепции языка.
в struct тег
new
ключевое слово напрасно сбивает с толку. Он ничего не делает. Это просто необходимо, если вы хотите использовать конструктор. Это делает не выполнитьnew
.обычное значение
new
Это выделить постоянное хранилище(в куче.) Такой язык, как C++ позволяетnew myObject()
или простоmyObject()
. Оба вызова одного и того же конструктора. Но первый создает новый объект и возвращает указатель. Последний просто создает темп. Любая структура или класс может используйте любой из них.new
выбор есть, и это что-то значит.C# не дает вам выбора. Классы всегда находятся в куче, а структуры всегда находятся в стеке. Это не возможно, чтобы выполнить настоящий
new
структуры. Опытные программисты C# привыкли к этому. Когда они увидятms = new MyStruct();
они знают, что игнорироватьnew
Как только синтаксис. Они знают, что это действует какms = MyStruct()
, который просто присваивает существующий объект.как ни странно(?), классы требуют
new
.c=myClass();
не допускается (использование конструктора для задания параметров существующего объектаc
.) Вы должны были бы сделать что-то вродеc.init();
. Таким образом, у вас действительно никогда не было выбора-конструкторы всегда выделяют для классов и никогда для структур. Элементnew
это всегда просто украшение.я предполагаю, что причина требует подделки
new
's в структуры, так что вы можете легко изменить структуру в класс (при условии, что вы всегда использоватьmyStruct=new myStruct();
когда вы впервые заявляете, что рекомендуемый.)