Home > Enterprise >  When are defaults supplied in C# constructors?
When are defaults supplied in C# constructors?

Time:01-19

I am looking at this in C#:

namespace R3.Geometry
{
    public class Tile
    {
        public Tile()
        {
            Isometry = new Isometry();
            EdgeIncidences = new List<Tile>();
            VertexIndicences = new List<Tile>();
        }

        public Tile( Polygon boundary, Polygon drawn, Geometry geometry )
            : this()
        {
            Boundary = boundary;
            Drawn = drawn;
            Geometry = geometry;
            VertexCircle = boundary.CircumCircle;
        }

        public Isometry Isometry { get; set; }
        public Polygon Boundary { get; set; }
        public Polygon Drawn { get; set; }
        public CircleNE VertexCircle { get; set; }
        public Geometry Geometry { get; set; }

        public Tile Clone()
        {
            Tile newTile = new Tile();
            newTile.Boundary = Boundary.Clone();
            newTile.Drawn = Drawn.Clone();
            newTile.VertexCircle = VertexCircle.Clone();
            newTile.Geometry = Geometry;
            return newTile;
        }

        // ...rest...
    }
}

I am porting this C# to TypeScript (I am new to C#). From my reading/understanding so far, the get; set "properties" don't have any defaults. The : this() on the second constructor means that second constructor calls into the first before it calls into itself, I'm pretty sure.

My question now is, are there any other defaults that get created or hidden/magical things that might happen? For example, in the Clone function, it calls Boundary.Clone(), but Boundary is never initialized if you just do let tile = new Tile(). Am I correct? Or what am I missing? Won't that cause an error?

If you call a constructor without any arguments, I feel like I might have read somewhere that it calls one of the constructors later in the chain with "default arguments" passed in. Is this the case somehow? That is, does Boundary, Draw, etc. always get created in this situation? What is the general flow if so?

If not, it seems there are two definitions of the Tile here, each with a different set of properties...

I also see this, with 2 constructors, both with : this, what does that mean?

    public struct TilingConfig
    {
        public TilingConfig( int p, int q, int maxTiles ) : this() 
        {
            SetupConfig( p, q, maxTiles );
        }

        public TilingConfig( int p, int q ) : this()
        {
            if( Geometry2D.GetGeometry( p, q ) != Geometry.Spherical )
                throw new System.ArgumentException();

            SetupConfig( p, q, PlatonicSolids.NumFacets( p, q ) );
        }

        // no more constructors.
    }

For complex object classes/structs, if they are defined in parameters, do they get defaulted, like Polygon boundary in the Tile definition?

CodePudding user response:

In your code public Tile() sets default values for the properties Isometry, EdgeIncidences, and VertexIndicences, and not for the properties Boundary, Drawn, VertexCircle and Geometry. these will not have any default values. new Tile() calls the default constructor that is public Tile(). Inside the Clone method also you are calling the default constructor only.

using the default constructor will not give any error but you won't be able to use Boundary, Drawn, VertexCircle, and Geometry, as these are not as you have not assigned them any value. and if you try to access you may get null reference exception.

To answer your second question.

<YourConstructor> : this() means that the constructor calls the default constructor before executing its own code. if any default value or initialization should happen that will be done before this constructor code is executed. Its called the Constructor chaining.

CodePudding user response:

You are on the right track -- but may need to analyze the flow carefully. The use of the : this() keyword here is called "constructor chaining" as discussed here.

As per that answer, it is a shorthand way to say:

Run the specified constructor before the current constructor

And here is another good answer discussing constructor chaining.

In addition, in your second example, you are dealing with a struct, while in your first example you are dealing with a class. This can get confusing as to how default values are handled with respect to the chaining. As per the MS article you linked, structs are value types versus classes which are reference types.

  • Related