1301

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?

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
Avi
  • 15,696
  • 9
  • 39
  • 54

14 Answers14

2045

Like this:

public Sample(string str) : this(int.Parse(str)) { }
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 68
    @Avi: You can make a `static` method that manipulates the parameters. – SLaks Oct 25 '10 at 11:26
  • 24
    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?) – Rosdi Kasim Dec 18 '13 at 16:49
  • 27
    @RosdiKasim: The base class constructor always runs first. You cannot use or see `this` until its base class has been initialized. – SLaks Dec 18 '13 at 16:59
  • This has a limitation: the shared code is limited to one expression per constructor's argument. E.g. I can't check `str` for `null`. – ivan_pozdeev Oct 09 '14 at 13:31
  • 5
    @ivan_pozdeev: Yes, you can; use `?:` or call a static method. – SLaks Oct 12 '14 at 01:17
  • @ivan_pozdeev, maybe you can do two constructors `public Sample(string str) : this(int.Parse(str))` and `public Sample() : this(0)`. It doesn't help if the user passes a `null` string as the argument, but it might be helpful in some cases. – bradlis7 Jan 08 '15 at 16:15
  • 1
    @SLaks I flagged your first comment (regarding static) as obsolete but it was declined. Would you mind explaining what that comment refers to? – default Feb 13 '15 at 09:56
  • 1
    @Default: IIRC, he was asking how to run more logic on the ctor parameters before calling a different ctor. – SLaks Feb 13 '15 at 15:33
  • @Slaks did you really mean to say "static" there though? A "private" method like "Init" would be appropriate, not a "static" method (how could that access local fields?) – George Birbilis Sep 05 '15 at 20:09
  • 5
    @GeorgeBirbilis: Yes. He wanted to run code (on the parameters) before calling the other ctor. At that point, there is no instance. – SLaks Sep 06 '15 at 01:42
  • Such code won't be able to write to any fields in the class, so what would be the purpose of it? – George Birbilis Sep 07 '15 at 18:36
  • 3
    @GeorgeBirbilis: To validate or transform the parameters. – SLaks Sep 07 '15 at 19:10
  • I prefer to use an Init method in that case and call it from all constructors, or use a constructor that has all the parameters and others with less parameters call into it with default values for their own missing parameters. BTW, I see .NET gradually shifting away from the multiple-constructors paradigm that Java also used and going into patterns like new Point() { X=..., Y=... }. If I remember well X and Y in that case can also be properties, not just fields, so they can encapsulate their own validation logic if it is atomic (that is one doesn't need to validate the X,Y pair, but X&Y alone) – George Birbilis Sep 08 '15 at 10:09
  • 2
    @GeorgeBirbilis: Actually, .Net is gradually moving away from that pattern, since it doesn't work with immutable types. – SLaks Sep 08 '15 at 14:13
202

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);
}
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
supercat
  • 77,689
  • 9
  • 166
  • 211
  • 24
    +1 real solution. Using `base(...)` or `this(...)` we can only perform very limited operations. – shashwat Sep 17 '12 at 09:32
  • 5
    How about using the `out` keyword instead of `ref`? – Jeppe Stig Nielsen Sep 13 '13 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 Sep 13 '13 at 20:35
  • Why `ref`? Why not avoid that parameter at all and let the `setupStuff` method directly set the member variable? – nawfal Nov 09 '13 at 12:46
  • 10
    @nawfal: Because it can't do so if the variable is `readonly`. – supercat Nov 10 '13 at 23:38
  • `setupStuff` can also return the `int` instead of it being passed in as a `ref` (or `out`) parameter. – Frank Bryce Jan 07 '16 at 15:23
  • 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 Jan 09 '16 at 17:50
  • 1
    Alternative version, for situations where it makes sense to have one constructor call another: `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`. – ToolmakerSteve May 05 '18 at 12:04
  • The solution is reasonable but it can be painful when the number of read-only fields increases ( you end up with a method with a lot of `ref`). Static methods that return calculated results and set the readonly to the return values can be an alternative. – joe Mar 30 '21 at 05:22
  • @joe: One can minimize the number of `ref` arguments by using a readonly instance of a private structure type with public fields (not properties!). Some people dislike such structures because they behave like a bunch of fields stuck together with duct tape rather than like objects, but what one needs is a a bunch of fields together with duct tape, using an exposed-field structure for that purpose (which *is* a bunch of duct-taped fields) makes a lot more sense than trying to make a structure do a bad imitation of an object doing a bad imitation of a joined bunch of fields. – supercat Mar 30 '21 at 05:29
78

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.
   }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sudantha
  • 15,684
  • 43
  • 105
  • 161
  • 20
    Unfortunately, does not work if I need some operations on arguments between constructors calls. – Denis Jul 12 '13 at 17:01
  • 1
    @Denis Can't you chain a constructor in the middle to achieve the same effect? – danyim Jun 05 '15 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. – Abdullah Shoaib Aug 04 '16 at 07:35
  • 1
    @AbdullahShoaib not when you need to call a parent constructor. – Hutch Moore Mar 19 '20 at 19:29
15

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);
    }
}
Faisal Mq
  • 5,036
  • 4
  • 35
  • 39
  • 4
    This would possibly allow a third party to create a Sample without setting it up, by calling `new Sample(str, false)`. – Teejay Oct 09 '13 at 09:53
  • 1
    This doesn't compile. – kayleeFrye_onDeck Jan 15 '16 at 03: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. – ToolmakerSteve May 05 '18 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`. – ToolmakerSteve May 05 '18 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();
        }
    }
pasx
  • 2,718
  • 1
  • 34
  • 26
  • 1
    This is potentially much cleaner if you are using the default constructor fur some cases, and making small/specific changes for others. – Adam Tolley Nov 25 '14 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()
    }

}
  • 3
    Just for sake of overall answer - if your constructor should initialize any readonly fields, you can't use methods for this. – lentinant Jul 12 '16 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();
        }
    }
SUNIL DHAPPADHULE
  • 2,755
  • 17
  • 32
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

Martin Backasch
  • 1,829
  • 3
  • 20
  • 30
Lineesh K Mohan
  • 1,702
  • 14
  • 18
3

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;
        }
}
Kasper Jensen
  • 548
  • 5
  • 12
1

Please, please, and pretty please do not try this at home, or work, or anywhere really.

This is a way solve to a very very specific problem, and I hope you will not have that.

I'm posting this since it is technically an answer, and another perspective to look at it.

I repeat, do not use it under any condition. Code is to run with LINQPad.

void Main()
{
    (new A(1)).Dump();
    (new B(2, -1)).Dump();
    
    var b2 = new B(2, -1);
    b2.Increment();
    
    b2.Dump();
}

class A 
{
    public readonly int I = 0;
    
    public A(int i)
    {
        I = i;
    }
}

class B: A
{
    public int J;
    public B(int i, int j): base(i)
    {
        J = j;
    }
    
    public B(int i, bool wtf): base(i)
    {
    }
    
    public void Increment()
    {
        int i = I + 1;

        var t = typeof(B).BaseType;
        var ctor = t.GetConstructors().First();
        
        ctor.Invoke(this, new object[] { i });
    }
}

Since constructor is a method, you can call it with reflection. Now you either think with portals, or visualize a picture of a can of worms. sorry about this.

Erdogan Kurtur
  • 3,630
  • 21
  • 39
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.

Mark Ainsworth
  • 811
  • 8
  • 24
0

In case you need to run something before calling another constructor not after.

public class Sample
{
    static int preprocess(string theIntAsString)
    {
        return preprocess(int.Parse(theIntAsString));
    }

    static int preprocess(int theIntNeedRounding)
    {
        return theIntNeedRounding/100;
    }

    public Sample(string theIntAsString)
    {
        _intField = preprocess(theIntAsString)
    }

    public Sample(int theIntNeedRounding)
    {
        _intField = preprocess(theIntNeedRounding)
    }

    public int IntProperty  => _intField;

    private readonly int _intField;
}

And ValueTuple can be very helpful if you need to set more than one field.

Keep Thinking
  • 141
  • 1
  • 7
0

NOTE: most of the solutions above does not work for structs.

Unfortunately initializing struct fields in a method called by a constructor is not recognized by the compiler and will lead to 2 errors:

  • in the constructor: Field xxxx must be fully assigned...
  • in the method, if you have readonly fields: a read-only field cannot be assigned except in a constructor.

These can be really frustrating for example when you just need to do simple check to decide on which constructor to orient your call to.

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

}
Zoyeb Shaikh
  • 301
  • 1
  • 11