5

I've been reading a lot about why constructors are useful and all the resources I found specify that constructors are used to initialize the instances of your classes. A key benefit of using a constructor is that it guarantees that the object will go through proper initialization before being used, often accepting parameters. It helps ensure the integrity of the object and helps make applications written with object-oriented languages much more reliable.

By default in C# a default empty constructor is instantiated if no constructors are specified in a class.

Most examples I'm finding specify something like this;

public Car(int speedCurrent, int gearCurrent) {
    speed = speedCurrent;
    gear= startGear;
}

Car myCar = new Car(0, 0);

Now what's the practical point of creating the constructor when you can specify the properties;

public int speed { get; set; }
public int gear { get; set; }

And initialise it like this;

Car myCar = new Car();
myCar.speed = 0;
myCar.gear = 0;

I cannot wrap my head around the need of having the explicitly creating a constructor. I would appreciate if someone would give me a good practical example.

7
  • I think that you are over thinking this. A property is great if you want to modify that value outside of the constructor. The constructor simply initialises a value when the object is created. For something like speed, this will inevitably change through the course of the objects lifetime, so a property is a good way to alter this value. Commented Apr 13, 2016 at 15:00
  • In your case it would be hard to see the benefit. But if for example you need to perform some type of logic to populate the properties in the class then it makes alot of sense. Really I think its a personal preference. Commented Apr 13, 2016 at 15:00
  • Clean, easily readable code. One of the most important reasons you've already given yourself, ensuring proper initialisation. If a method relies on properly set fields and properties it needs a good constructor. But if you're going to set properties after initializing, also check this for better readability msdn.microsoft.com/en-us/library/bb384062.aspx Commented Apr 13, 2016 at 15:02
  • What if the properties are read-only? The only way to set them is through a constructor. Commented Apr 13, 2016 at 15:02
  • Essentially your question is "why to use OOP/encapsulation at all"... And you are right - there is none, except some people like it (there are some other "small" benefits too, but nothing is strictly required - one can use assembly to write code just fine) Commented Apr 13, 2016 at 15:03

10 Answers 10

11

Although you can initialize the properties like what you show:

Car myCar = new Car();
myCar.speed = 0;
myCar.gear = 0;

without constructor, you may also choose not to initialize any of the properties

Car myCar = new Car();

Which may cause the class to work poorly/not working at all.

The purpose of the constructor is to force you to initialize all the required properties (by design) before you are allowed to use the class instance.

This is especially useful if you consider a case where you work in a project with multiple team members. If your team members want to use your class, by having right constructor, you can already hint to them what properties needed to be initialized in the class in order for them to use the class properly.

Sign up to request clarification or add additional context in comments.

Comments

6

Now what's the practical point of creating the constructor when you can specify the properties;

The benefit of having a non-default constructor is that you are forced to pass all required dependencies into it. This guarantees that when instaniated, the object will have everything that is required for it to function properly.

Comments

3

Now what's the practical point of creating the constructor when you can specify the properties

There are four problems with the approach that exposes properties:

  • You cannot ensure consistency after initialization - For example, if you want to make sure that non-zero speed requires a non-zero gear, you no longer have control over this check
  • You cannot ensure consistency when multiple attributes must be updated atomically - In concurrent situations when both speed and gear must be updated at the same time guarded by a lock the approach with independently exposed attributes is not going to be reliable
  • You are forced to make your object mutable - This is not always desirable, especially when your object is designed for concurrent use
  • You are forced to expose methods that your users may not need - Even in situations when your users expect a mutable object it may not be desirable to expose individual setters; with this approach you have no other choice.

I cannot wrap my head around the need of having the explicitly creating a constructor.

Here is a brief demonstration of what you can do when your setters are not exposed:

class Car {
    private readonly object lockObject = new object();
    private int speed;
    private int gear;
    public int Speed {
        lock (lockObject) {
            return speed;
        }
    }
    public int Gear {
        lock (lockObject) {
            return gear;
        }
    }
    public int Gear{ get; }
    public Car(int speed, int gear) {
        // You can validate two attributes together
        if (speed != 0 && gear == 0) {
            throw new ArgumentException("Non-zero speed in zero gear");
        }
        this.speed = speed;
        this.gear= gear;
    }
    public void SpeedUp(int increase) {
        lock(lockObject) {
            var newSpeed = Math.Max(Speed + increase, 0);
            if (newSpeed > 200) {
                 throw new InvalidOperationexception("Cannot speed up past 200");
            }
            // Concurrent users would not see inconsistent speed setting
            Speed = newSpeed;
            Gear = Speed / 25;
        }
    }
}

The main advantages are your ability to make simultaneous adjustments in concurrent environments, and a way to ensure consistency of the initial object.

Comments

1

The practical point in your example is that you don't need to do a new Car(0, 0); for instantiating but instead just do this for a default initialization:

public Car() {
    speed = 0;
    gear = 0;
}

Car myCar = new Car();

Comments

1

Non default constructor enforces the client of your class to provide parameters. Initializing by properties a) is not required by code b) can expose class not yet ready to use. Besides, you might want to hide speed or gear properties from others.

Comments

1

Depending on what your class does, you may want to do some initialization. For example, a class might hook a static event when it's initialized, or output to debug.. while coding it also gives you a point you can set a breakpoint to break on any attempt to instantiate the class.

Comments

1

The problem is that your users of the Car class need to somehow know that they need to set the initial speed and gear of the car.

The rule guideline i follow is that the constructor should create an object that is 100% ready to use.

Comments

1

The concept of constructors is pretty old school. It hails back to the days of C and C++ when you managed all your pointers yourself. The constructor would set up most of the nillable variables to ensure you didn't get a general protection fault or segmentation fault in executing the code.

Modern coders avoid constructors that take parameters. This is due to the difficulty they cause when performing automated unit testing. It is perfectly OK to use classes that have only default constructors (constructors with no arguments) and initialize them with calls to properties or methods after the fact.

6 Comments

I've never heard of that reason to avoid constructors that have parameters. What's the difficulty with automated testing that you mention?
I must be misunderstanding something, because it looks to me like that article recommends using a constructor which takes a parameter (in the particular case that the article talks about).
That's called dependency injection, specifically Constructor Injection, which is one of a few ways to do it. Setter injection does not use constructor parameters.
The parameters provided during constructor injection are global... they should be resolved by AutoFac, which can be configured differently in the unit testing scenario and thus isolated from the executing code. Other types of constructor parameters (e.g. business logic parameters passed inline in code) cause the problems in unit testing.
|
1

I would say this would come down to how you want to achieve the objective of the class you are constructing.

In OO Programming to achieve encapsulation you would only access the members via getters/setters. Again this depends on how far you want to go with implementing OO principals.

An example of when you should pass the variables into the constructor is if you had some initialization code in the constructor that needed those values.

private int speed { get; set; }
private int gear { get; set; }
private bool reduceSpeed { get; set; }

public Car(int speedCurrent, int gearCurrent) {
    speed = speedCurrent;
    gear= startGear;
    if (speed > 30)
        reduceSpeed = true; // do further processing with this.
    ...
}

Comments

0

Constructors in C#: (In simple Theory)

  • Is a special type of function/method which has the same name as its class.
  • It is invoked automatically whenever an object of a class is created.
  • It is also responsible for object initialization and memory allocation of its class members.
  • It doesn’t have a return a type, not even a void type.
  • Supports overloading by using parameterized constructor.

They are of 4 types:

enter image description here

Default Constructor:

The default constructor has no parameters. When a class has no constructor, default constructor is served by the compiler to that class. If you don’t define any constructor then default constructor is defined by the compiler. It is used to assign default values to instance variables of class

Example:

namespace Default_parameterizedConstructor
{
    public class Student
    {
        // instance members
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string College { get; set; }

        //default constructor parameters less
        public Student()
        {
            College = "My College"; //explicit default value for college
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Object instance of Student.
            Student st = new Student();
            Console.WriteLine("Student details are Student ID: {0}, Student Name: {1}, College :{2}", st.StudentId, st.Name, st.College);
            Console.ReadKey();
        }
    }
}

The output for Default Constructor will be as: "Student details are Student ID: 0, Student Name: , College :My College"

Parameterized Constructor: The parameterized constructor has one or more parameters. We use when we have to pass one or more parameter so that we can set the parameters of the class instance members. Used to assign values to instance variables of class. We use this keyword when the instance member name and the constructor receiving parameter are same in this case it is mandatory to specify this keyword. If names are different then it is optional to use this keyword.

Now, Lets take the above example with parameterized constructor:

namespace Default_parameterizedConstructor
{

    public class Student
    {
        // instance members
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string College { get; set; }

        //default constructor parameters less
        public Student()
        {
            College = "My College"; //explicit default value for college
        }
        // parameterised constructor
        public Student(int studentid, string name, string college)
        {
            this.StudentId = studentid;
            this.Name = name;
            this.College = college;

        }
        public Student(int studentid, string name)
        {
            this.StudentId = studentid;
            this.Name = name;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //default constructor parameter
            //Object instance of Student.
            Student st = new Student();
            Console.WriteLine("The output for Default Constructor are Student ID: {0}, Student Name: {1}, College :{2}", st.StudentId, st.Name, st.College);
            
            
            // parameterised constructor
            //Operator overloading happening.
            Student st1 = new Student(1, "John Doe", "MIT");
            Console.WriteLine("The output for Default Constructor are Student ID: {0}, Student Name: {1}, College :{2}", st1.StudentId, st1.Name, st1.College);

            // parameterised constructor with operator overloading
            Student st2 = new Student(1,"Jimmy");
            Console.WriteLine("The output for Default Constructor are Student ID: {0}, Student Name: {1}, College :{2}", st2.StudentId, st2.Name, st2.College);

            Console.ReadKey();
        }
    }
}

*The Output will be as follows: //First

The output for Default Constructor are Student ID: 0, Student Name: , College :My College

//Second

The output for Default Constructor are Student ID: 1, Student Name: John Doe, College :MIT

//Third

The output for Default Constructor are Student ID: 1, Student Name: Jimmy, College :*

Static Constructor: A special type of constructor that gets called before the first object of the class is created. Used to initialize any static fields, or to perform a particular action that need to perform only once. A class can have only one static constructor and it must be a default constructor, having no access modifier.

Private Constructor: Restrict a class external instantiation but in nested class you can create instance of this class. In C# 1 X there was no static class, so developer used private constructor to prevent a class external instantiation. Used to implement singleton pattern i.e. a single instance for a class. A class can have multiple private constructors and public constructors.

If you don’t create an instance how will you access the value? We can do that by making the member of the class as private static. Only static members are available using the class name.

Let look both by an example below:

namespace StaticAndPrivate
{
    public class Example
    {
        private static int Counter;

        //private constructor
        private Example()
        {
            Counter = 10;
        }

        //static constructor
        static Example()
        {
            Counter = 20;
        }

        //public constructor
        public Example(int counter)
        {
            Counter = Counter + counter;
        }

        public static int GetCounter()
        {
            return ++Counter;
        }

        public class NestedExample
        {
            public void Test()
            {
                //internal instance
                Example ex = new Example();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //external instance
            //Example ex = new Example();

            Example ex = new Example(10);
            Console.WriteLine("Counter : {0}", Example.GetCounter());

            Console.ReadKey();
        }
    }
}

Hope this explains the concept with an example.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.