What does the keyword "new" do to a struct in C#?

Catch Eric Lippert's excellent answer from this thread. To quote him:

When you "new" a value type, three things happen. First, the memory manager allocates space from short term storage. Second, the constructor is passed a reference to the short term storage location. After the constructor runs, the value that was in the short-term storage location is copied to the storage location for the value, wherever that happens to be. Remember, variables of value type store the actual value.

(Note that the compiler is allowed to optimize these three steps into one step if the compiler can determine that doing so never exposes a partially-constructed struct to user code. That is, the compiler can generate code that simply passes a reference to the final storage location to the constructor, thereby saving one allocation and one copy.)

(Making this answer since it really is one)


In a struct, the new keyword is needlessly confusing. It doesn't do anything. It's just required if you want to use the constructor. It does not perform a new.

The usual meaning of new is to allocate permanent storage (on the heap.) A language like C++ allows new myObject() or just myObject(). Both call the same constructor. But the former creates a new object and returns a pointer. The latter merely creates a temp. Any struct or class can use either. new is a choice, and it means something.

C# doesn't give you a choice. Classes are always in the heap, and structs are always on the stack. It isn't possible to perform a real new on a struct. Experienced C# programmers are used to this. When they see ms = new MyStruct(); they know to ignore the new as just syntax. They know it's acting like ms = MyStruct(), which merely assigns to an existing object.

Oddly(?), classes require the new. c=myClass(); isn't allowed (using the constructor to set values of existing object c.) You'd have to make something like c.init();. So you really never have a choice -- constructors always allocate for classes, and never for structs. The new is always just decoration.

I assume the reason for requiring fake new's in structs is so you can easily change a struct into a class (assuming you always use myStruct=new myStruct(); when you first declare, which is recommended.)


Using "new MyStuct()" ensures that all fields are set to some value. In the case above, nothing is different. If instead of setting ms.name you where trying to read it, you would get a "Use of possible unassigned field 'name'" error in VS.


From struct (C# Reference) on MSDN:

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

To my understanding, you won't actually be able to use a struct properly without using new unless you make sure you initialise all the fields manually. If you use the new operator, then a properly-written constructor has the opportunity to do this for you.

Hope that clears it up. If you need clarification on this let me know.


Edit

There's quite a long comment thread, so I thought I'd add a bit more here. I think the best way to understand it is to give it a go. Make 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 around with it. Remove the constructors and see what happens. Try using a constructor that only initialises one variable(I've commented one out... it won't compile). Try with and without the new keyword(I've commented out some examples, uncomment them and give them a try).

Tags:

C#

Object

Struct