1358

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,3373 gold badges28 silver badges44 bronze badges
asked Oct 24, 2010 at 16:06
0

11 Answers 11

2147

Like this:

public Sample(string str) : this(int.Parse(str)) { }
AustinWBryan
3,3373 gold badges28 silver badges44 bronze badges
answered Oct 24, 2010 at 16:09
Sign up to request clarification or add additional context in comments.

14 Comments

@Avi: You can make a static method that manipulates the parameters.
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?)
@RosdiKasim: The base class constructor always runs first. You cannot use or see this until its base class has been initialized.
@ivan_pozdeev: Yes, you can; use ?: or call a static method.
@GeorgeBirbilis: Yes. He wanted to run code (on the parameters) before calling the other ctor. At that point, there is no instance.
|
207

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,3373 gold badges28 silver badges44 bronze badges
answered Jul 22, 2011 at 20:52

12 Comments

+1 real solution. Using base(...) or this(...) we can only perform very limited operations.
How about using the out keyword instead of ref?
@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.
@nawfal: Because it can't do so if the variable is readonly.
@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.
|
81

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
31.5k22 gold badges110 silver badges134 bronze badges
answered Oct 24, 2010 at 16:12

4 Comments

Unfortunately, does not work if I need some operations on arguments between constructors calls.
@Denis Can't you chain a constructor in the middle to achieve the same effect?
@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.
@AbdullahShoaib not when you need to call a parent constructor.
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);
 }
}
answered Nov 28, 2012 at 13:07

4 Comments

This would possibly allow a third party to create a Sample without setting it up, by calling new Sample(str, false).
This doesn't compile.
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.
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.
11

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();
 }
 }
answered May 23, 2014 at 0:17

1 Comment

This is potentially much cleaner if you are using the default constructor fur some cases, and making small/specific changes for others.
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()
 }
}
answered Jun 7, 2016 at 20:42

1 Comment

Just for sake of overall answer - if your constructor should initialize any readonly fields, you can't use methods for this.
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();
 }
 }
answered Oct 10, 2018 at 14:21

Comments

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,8993 gold badges24 silver badges34 bronze badges
answered Mar 31, 2015 at 3:52

Comments

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;
 }
}
answered Sep 6, 2019 at 9:30

1 Comment

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.
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.

answered Jul 22, 2022 at 17:22

Comments

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);
 }
 }
}
answered May 8, 2023 at 0:41

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.