What does the "new" keyword do for a C # structure?

In C #, structures are managed in terms of values, and objects are referenced. In my opinion, when creating an instance of a class, the new keyword forces C # to use the class information to instantiate it, as shown below:

 class MyClass { ... } MyClass mc = new MyClass(); 

For struct, you are not creating an object, but simply setting the variable to a value:

 struct MyStruct { public string name; } MyStruct ms; //MyStruct ms = new MyStruct(); ms.name = "donkey"; 

What I don’t understand is if you declare the variables MyStruct ms = new MyStruct() , what does the new keyword do here for approval? If the struct cannot be an object, then what instance of new is created here?

+56
object c # struct
Feb 09 '12 at 8:27
source share
6 answers

From struct (C# Reference) to MSDN:

When you create a struct object using the new operator, it is created and the corresponding constructor is called. Unlike classes, structures can be created without using a new operator. If you do not use the new one, the fields will remain unassigned, and the object cannot be used until all fields are initialized.

As far as I understand, you can’t actually use the structure correctly without using a new one unless you make sure that you manually initialize all the fields. If you use a new operator, the constructor will do it for you.

Hope this clears up. If you need clarification, let me know.




Edit

There is a rather long stream of comments there, so I thought I would add a little more. I think the best way to understand this is to let him go. Create a console project in Visual Studio called "StructTest" and copy the following code into it.

 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); } } } 

Play with him. Remove the constructors and see what happens. Try using a constructor that initializes only one variable (I commented on one of them ... it will not compile). Try with a new keyword and without it (I commented on some examples, uncomment them and try).

+50
Feb 09 '12 at 8:30
source share

Catch Eric Lippert is a great answer from this thread. To quote it:

When you are a β€œnew” type of meaning, three things happen. First, the memory manager allocates space from short-term storage. Secondly, a short-term storage reference is passed to the constructor. After starting the constructor, the value that was in the short term, the storage location is copied to the store for the value, wherever it happens. Remember that value store variables are the actual value.

(Note that the compiler is allowed to optimize these three steps in one step if the compiler can determine that it never provides a partially constructed structure for user code. That is, the compiler can generate code that simply passes the link to the destination memory location to the constructor , thereby preserving one distribution and one copy.)

(Executing this answer since it is really one)

+15
Jun 09 '13 at 12:43 on
source share

Using "new MyStuct ()" ensures that all fields are set to some value. In the above case, nothing has changed. If instead of setting ms.name where you are trying to read it, you get "Using a possible invalid field name" name "in VS.

+3
Feb 09 2018-12-12T00:
source share

Each time an object or structure arises, all its fields also arise; if any of these fields are structure types, all nested fields also appear. When an array is created, all its elements arise (and, as indicated above, if any of these elements is a structure, the fields of these structures also appear). All this happens before any constructor code has the ability to run.

In .net, the structure constructor is actually nothing more than a method that takes the structure as the "out" parameter. In C #, an expression that calls the constructor of a struct will allocate a temporary instance of struct, call its constructor, and then use that temporary instance as the value of the expression. Please note that this is different from vb.net, where the generated code for the constructor will start by resetting all fields, but where the code from the caller will try to make the constructor work directly with the destination. For example: myStruct = new myStructType(whatever) in vb.net will clear myStruct before the first constructor statement is executed; inside the constructor, any record in the object that will be built will immediately work with myStruct .

+3
Feb 09 2018-12-12T00:
source share

ValueType and structures are something special in C #. Here I show you what happens when you get something new.

Here we have the following

  • The code

     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; } 

And the IL-generated test class methods will

  • 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.si // 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.si // 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 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 } 

The behavior of the methods is commented out in the IL code. And you can look at OpCodes.Initobj and OpCodes.Newobj . The value type is usually initialized by OpCodes.Initobj , but as MSDN says OpCodes.Newobj will also be used.

  • Description of OpCodes.Newobj

    Value types are usually not created using newobj. They are usually allocated either as arguments or local variables, using newarr (for null, one-dimensional arrays) or as object fields. Once selected, they are initialized using Initobj. However , the newobj command can be used to create a new instance of the value type on the stack, which can then be passed as an argument, stored on the local network, etc.

For each type of value that is numeric, from byte to double , it has a specific op code. Although they are declared as struct , there is some difference in the generated IL, as shown.

Here are two more things:

  • ValueType itself is declared an abstract class

    That is, you cannot enter it directly.

  • struct cannot contain explicit constructors without parameters

    That is, when you are a new a struct , you will get into the case above either from NewMyLong or NewMyLongWithValue .

To summarize , new to the types of values ​​and structures are designed to ensure consistency in the concept of language.

0
Mar 23 '13 at 21:58
source share

In the structure, the new keyword is uselessly confusing. He does not do anything. This is just required if you want to use the constructor. It does not execute new .

The usual new value is to allocate persistent storage (on the heap). A language like C ++ allows new myObject() or just myObject() . Both calls to the same constructor. But the first creates a new object and returns a pointer. The latter just creates a pace. Any structure or class can use either. new is a choice, and it means something.

C # doesn't give you a choice. Classes are always on the heap, and structures are always on the stack. Unable to execute real new in structure. For this, experienced programmers in C # are used. When they see ms = new MyStruct(); , they know they are ignoring new as just syntax. They know that it acts as ms = MyStruct() , which simply assigns an existing object.

Strange (?), Classes require new . c=myClass(); not allowed (using the constructor to set the values ​​of an existing object c .) You need to do something like c.init(); . Therefore, you really have no choice - constructors always allocate for classes, and never for structures. new always just a decoration.

I assume the reason for using fake new in structs is that you can easily change the structure into a class (if you always use myStruct=new myStruct(); on the first declaration, which is recommended).

-one
Dec 28 '15 at 23:02
source share



All Articles