1335

I have two constructors which feed values to readonly fields.

public class Sample
{
    public Sample(string theIntAsString)
    {
        int i = int.Parse(theIntAsString);
        _intField = i;
    }

    public Sample(int theInt) => _intField = theInt;
    public int IntProperty    => _intField;

    private readonly int _intField;
}

One constructor receives the values directly, and the other does some calculation and obtains the values, then sets the fields.

Now here's the catch:

  1. I don't want to duplicate the setting code. In this case, just one field is set but of course there may well be more than one.
  2. To make the fields readonly, I need to set them from the constructor, so I can't "extract" the shared code to a utility function.
  3. I don't know how to call one constructor from another.

Any ideas?

0

11 Answers 11

2102

Like this:

public Sample(string str) : this(int.Parse(str)) { }
14
  • 72
    @Avi: You can make a static method that manipulates the parameters.
    – SLaks
    Commented Oct 25, 2010 at 11:26
  • 25
    May I know the execution order of this one? Everything in Sample(string) will be executed first then Sample(int) or the int version will be executed first then it will get back to the string version? (Like calling super() in Java?) Commented Dec 18, 2013 at 16:49
  • 30
    @RosdiKasim: The base class constructor always runs first. You cannot use or see this until its base class has been initialized.
    – SLaks
    Commented Dec 18, 2013 at 16:59
  • 6
    @ivan_pozdeev: Yes, you can; use ?: or call a static method.
    – SLaks
    Commented Oct 12, 2014 at 1:17
  • 5
    @GeorgeBirbilis: Yes. He wanted to run code (on the parameters) before calling the other ctor. At that point, there is no instance.
    – SLaks
    Commented Sep 6, 2015 at 1:42
205

If what you want can't be achieved satisfactorily without having the initialization in its own method (e.g. because you want to do too much before the initialization code, or wrap it in a try-finally, or whatever) you can have any or all constructors pass the readonly variables by reference to an initialization routine, which will then be able to manipulate them at will.

public class Sample
{
    private readonly int _intField;
    public int IntProperty => _intField; 

    private void setupStuff(ref int intField, int newValue) => intField = newValue;

    public Sample(string theIntAsString)
    {
        int i = int.Parse(theIntAsString);
        setupStuff(ref _intField,i);
    }

    public Sample(int theInt) => setupStuff(ref _intField, theInt);
}
10
  • 25
    +1 real solution. Using base(...) or this(...) we can only perform very limited operations.
    – shashwat
    Commented Sep 17, 2012 at 9:32
  • 5
    How about using the out keyword instead of ref? Commented Sep 13, 2013 at 20:24
  • 1
    @JeppeStigNielsen: In this particular case it would likely be appropriate if the method only needed to store something there. On the other hand, the same approach could be used in cases where the caller would put something in the field and call a method that might or might not need to modify it; using out in the example might not make that clear. Also, I'm generally a bit skeptical of out, since there's no guarantee that an outside method with an out parameter will actually store anything there.
    – supercat
    Commented Sep 13, 2013 at 20:35
  • 10
    @nawfal: Because it can't do so if the variable is readonly.
    – supercat
    Commented Nov 10, 2013 at 23:38
  • 3
    @JohnCarpenter: If only one readonly field needs to be set, the code which sets it could call the method and assign the field using the return value, but any number of fields may be written directly with ref. Also, in case it matters, changes made via the ref parameter take place immediately, even before the function returns, while those made using a function return value would not.
    – supercat
    Commented Jan 9, 2016 at 17:50
79

Before the body of the constructor, use either:

: base (parameters)

: this (parameters)

Example:

public class People: User
{
   public People (int EmpID) : base (EmpID)
   {
      // Add more statements here.
   }
}
4
  • 20
    Unfortunately, does not work if I need some operations on arguments between constructors calls.
    – Denis
    Commented Jul 12, 2013 at 17:01
  • 1
    @Denis Can't you chain a constructor in the middle to achieve the same effect?
    – danyim
    Commented Jun 5, 2015 at 14:08
  • 6
    @Denis you cannot do anything before you call a constructor. If you want to do something before initializing an object's properties, move initialization in a method other than the constructor example init(). You can call this method from any of your constructors. Commented Aug 4, 2016 at 7:35
  • 1
    @AbdullahShoaib not when you need to call a parent constructor. Commented Mar 19, 2020 at 19:29
16

I am improving upon supercat's answer. I guess the following can also be done:

class Sample
{
    private readonly int _intField;
    public int IntProperty
    {
        get { return _intField; }
    }

    void setupStuff(ref int intField, int newValue)
    {
        //Do some stuff here based upon the necessary initialized variables.
        intField = newValue;
    }

    public Sample(string theIntAsString, bool? doStuff = true)
    {
        //Initialization of some necessary variables.
        //==========================================
        int i = int.Parse(theIntAsString);
        // ................
        // .......................
        //==========================================

        if (!doStuff.HasValue || doStuff.Value == true)
           setupStuff(ref _intField,i);
    }

    public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times
    {
        setupStuff(ref _intField, theInt);
    }
}
4
  • 4
    This would possibly allow a third party to create a Sample without setting it up, by calling new Sample(str, false).
    – Teejay
    Commented Oct 9, 2013 at 9:53
  • 1
    This doesn't compile. Commented Jan 15, 2016 at 3:02
  • 1
    This is not good approach; confusing; unnecessarily complicated. If you call another constructor using this, then let that constructor call setupStuff; remove the call to setupStuff in the last constructor. Then you don't need the doStuff / false parameter. (A lesser complaint is that if you do have a reason to use doStuff parameter, there is no benefit to making that a nullable Boolean bool?. Just use bool.) Also, what Teejay pointed out, means this is a fatally flawed design. Commented May 5, 2018 at 11:43
  • 1
    Better code might be: public Sample(string theIntAsString) : this(int.Parse(theIntAsString)) {} public Sample(int theInt) { setupStuff(ref _intField, theInt); } Note that the first constructor, which calls another constructor, does not call setupStuff. Commented May 5, 2018 at 12:01
10

Here is an example that calls another constructor, then checks on the property it has set.

    public SomeClass(int i)
    {
        I = i;
    }

    public SomeClass(SomeOtherClass soc)
        : this(soc.J)
    {
        if (I==0)
        {
            I = DoSomethingHere();
        }
    }
1
  • 1
    This is potentially much cleaner if you are using the default constructor fur some cases, and making small/specific changes for others. Commented Nov 25, 2014 at 23:15
9

Yeah, you can call other method before of the call base or this!

public class MyException : Exception
{
    public MyException(int number) : base(ConvertToString(number)) 
    {
    }

    private static string ConvertToString(int number) 
    { 
      return number.toString()
    }

}
1
  • 3
    Just for sake of overall answer - if your constructor should initialize any readonly fields, you can't use methods for this.
    – lentinant
    Commented Jul 12, 2016 at 14:10
8

Constructor chaining i.e you can use "Base" for Is a relationship and "This" you can use for same class, when you want call multiple Constructor in single call.

  class BaseClass
{
    public BaseClass():this(10)
    {
    }
    public BaseClass(int val)
    {
    }
}
    class Program
    {
        static void Main(string[] args)
        {
            new BaseClass();
            ReadLine();
        }
    }
5

When you inherit a class from a base class, you can invoke the base class constructor by instantiating the derived class

class sample
{
    public int x;

    public sample(int value)
    {
        x = value;
    }
}

class der : sample
{
    public int a;
    public int b;

    public der(int value1,int value2) : base(50)
    {
        a = value1;
        b = value2;
    }
}

class run 
{
    public static void Main(string[] args)
    {
        der obj = new der(10,20);

        System.Console.WriteLine(obj.x);
        System.Console.WriteLine(obj.a);
        System.Console.WriteLine(obj.b);
    }
}

Output of the sample program is

50 10 20


You can also use this keyword to invoke a constructor from another constructor

class sample
{
    public int x;

    public sample(int value) 
    {
        x = value;
    }

    public sample(sample obj) : this(obj.x) 
    {
    }
}

class run
{
    public static void Main(string[] args) 
    {
        sample s = new sample(20);
        sample ss = new sample(s);

        System.Console.WriteLine(ss.x);
    }
}

The output of this sample program is

20

2

Error handling and making your code reusable is key. I added string to int validation and it is possible to add other types if needed. Solving this problem with a more reusable solution could be this:

public class Sample
{
    public Sample(object inputToInt)
    {
        _intField = objectToInt(inputToInt);
    }

    public int IntProperty => _intField;

    private readonly int _intField;
}

public static int objectToInt(object inputToInt)
{
    switch (inputToInt)
        {
            case int inputInt:
                return inputInt;
            break;
            case string inputString:
            if (!int.TryParse(inputString, out int parsedInt))
            {
                throw new InvalidParameterException($"The input {inputString} could not be parsed to int");
            }
            return parsedInt;

            default:
                throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");
            break;
        }
}
1
  • Showing a different way to do it doesn't answer the question. And what if there are a dozen different fields and different ways of setting them? objectToInt won't help then.
    – Jim Balter
    Commented Sep 5, 2023 at 6:51
1

In my case, I had a main constructor that used an OracleDataReader as an argument, but I wanted to use different query to create the instance:

I had this code:

public Subscriber(OracleDataReader contractReader)
    {
        this.contract = Convert.ToString(contractReader["contract"]);
        this.customerGroup = Convert.ToString(contractReader["customerGroup"]);
        this.subGroup = Convert.ToString(contractReader["customerSubGroup"]);
        this.pricingPlan= Convert.ToString(contractReader["pricingPlan"]);
        this.items = new Dictionary<string, Member>();
        this.status = 0;
        
        
    }

So I created the following constructor:

public Subscriber(string contract, string customerGroup) : this(getSubReader(contract, customerGroup))
    { }

and this method:

 private static  OracleDataReader getSubReader(string contract, string customerGroup)
    { 
        cmdSubscriber.Parameters[":contract"].Value = contract + "%";
        cmdSubscriber.Parameters[":customerGroup"].Value = customerGroup+ "%";
        return  cmdSubscriber.ExecuteReader();
        
    }

notes: a statically defined cmdSubscriber is defined elsewhere in the code; My main constructor has been simplified for this illustration.

1
using System;
using System.Linq;
using System.Text;
using System.Threading;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer();
            customer.PrintFullName();

            Customer customer1 = new Customer("Zoyeb", "Shaikh");
            customer1.PrintFullName();
        }

    }

    public class Customer
    {
        string _firstName;
        string _lastName;

        public Customer(string fn, string ln)
        {
            _firstName = fn;
            _lastName = ln;
        }

        public Customer() : this("No-First Name","No-Last Name")
        {

        }
        public void PrintFullName()
        {
            Console.WriteLine("Full Name = {0}", this._firstName + " " + this._lastName);
        }
    }

}

Not the answer you're looking for? Browse other questions tagged or ask your own question.