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:
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.
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.
I don't know how to call one
constructor from another.
Any ideas?
Like this:
public Sample(string str) : this(int.Parse(str)) { }
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);
}
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.
}
}
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);
}
}
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();
}
}
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()
}
}
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();
}
}
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
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;
}
}
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.
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.
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.
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.
I am using a get set method to loop another method. As shown below, I am trying to increase the value of Table10_3 in the ValuesForTableLooping class. In the Main method, I have called the get set property to increase the value by one.
I have 2 questions at hand,
Is there a way to call the get set method without putting it as Inc.Val = 0;?
Why does changing any value in Inc.Val = 0; not affect the outcome?
class Class2
{
public class ValuesForTableLooping
{
public static int Table10_3 = 1;
}
public static void Main()
{
Console.WriteLine(ValuesForTableLooping.Table10_3);
Increase Inc = new Increase();
Inc.Val = 0;
Console.WriteLine(ValuesForTableLooping.Table10_3);
Inc.Val = 0;
Console.WriteLine(ValuesForTableLooping.Table10_3);
Inc.Val = 0;
Console.WriteLine(ValuesForTableLooping.Table10_3);
}
public class Increase
{
private int val;
public int Val
{
get { return val; }
set { val = ValuesForTableLooping.Table10_3++; }
}
}
}
Thank you so much once again!
Your design is pretty strange and you seem to have a great misunderstanding on what properties are.
A property is nothing - as you noticed - as a get- and a set-method. So you could achieve the exact same with the following code:
public int get_Val() { return val; }
public void set_Val(int value) { val = ValuesForTableLooping.Table10_3++; }
And here is the weird thing. A setter expects a new value for your property, which is provided as value. However you donĀ“t use that value at all in your implementation. Instead you just increase val by one, which I would call a really strange design. You either want to set the new value from the outside with this:
public void set_Val(int value) { val = value; }
or in the property-notation:
public int Val {
get { return val; }
set { val = value; }
}
which can be further simplified by using an auto-implemented property:
public int Val { get; set; }
Another - IMHO better - way is to omit the setter completely and create some IncreaseVal-method instead:
public void IncreaseVal() { ValuesForTableLooping.Table10_3++; }
Last but not least Increase is a very bad name for a class. It does not describe a thing, but something you can do with a thing.
This question already has answers here:
A property or indexer may not be passed as an out or ref parameter
(9 answers)
Closed 5 years ago.
So I have this class that holds 3 counters:
public class Files
{
private static ObservableCollection<Files> _files = new ObservableCollection<Files>();
private static int _inProcess;
private static int _finished;
private static int _inQueue;
public static ObservableCollection<Files> List
{
get { return _files ; }
set { _files = value; }
}
public static int InProcess
{
get { return _inProcess; }
set
{
_inProcess = value;
}
}
public static int Finished
{
get { return _finished; }
set
{
_finished = value;
}
}
public static int InQueue
{
get { return _inQueue; }
set
{
_inQueue = value;
}
}
}
And from another class I want to add value to this fields:
Interlocked.Increment(ref Files.InProcess);
But got this error:
A property or indexer may not be passed as an out or ref parameter.
This works fine:
Files.InProcess++;
How can i fix it ?
The error is pretty straightforward. You can't pass a property as ref. In this case the best option is to create a method
public static void IncrementInProcess()
{
Interlocked.Increment(ref _inProcess);
}
I have a class where I hold some variables :
public class PreviousCalls
{
private static int bot1Call;
public static int previousBot1Call
{
get { return bot1Call; }
set { bot1Call = value; }
}
private static int bot2Call;
public static int previousBot2Call
{
get { return bot2Call; }
set { bot2Call = value; }
}
private static int bot3Call;
public static int previousBot3Call
{
get { return bot3Call; }
set { bot3Call = value; }
}
private static int bot4Call;
public static int previousBot4Call
{
get { return bot4Call; }
set { bot4Call = value; }
}
private static int bot5Call;
public static int previousBot5Call
{
get { return bot5Call; }
set { bot5Call = value; }
}
}
I need to pass those variables as parameters to a lot of methods in my other class here's how I do it :
void AI(... , int previous)
AI(... , PreviousCalls.previousBot1Call);
So the parameter previous is changing the way it should but the variables from class PreviousCalls are not changing at all, why is that ?
int is value type, so there is a copy of 'previous value' passed to method body. So changing a variable inside method doesn't cause the original value change:
public void Test(int a)
{
a = 10;
}
int t = 11;
Test(t);
//t is still 11, because Test method operates on copy of t
To change original value you must use ref or out:
void AI(..., ref int previous) { ... }
int param;
AI(..., ref param); //when ref is used, original variable wil be changed.
PreviousCalls.previousBot1Call = param;
Unfortunately, you cannot use it like this:
AI(... , ref PreviousCalls.previousBot1Call); // compile-time error
// member-access is forbidden wtih out/ref
AI(,.., ref 10); // compile-time error
Another attempt:
interface IAIParam
{
int Previous { get; set; }
// other params
}
void AI(IAIParam p)
{
p.Previous += 1;
//....
}
And then implementaiton:
internal class MyBotProxy : IAIParam
{
public int Previous
{
get { return PreviousCalls.previousBot1Call; }
set { PreviousCalls.previousBot1Call = value; }
}
}
usage:
var myProxy = new MyBotProxy();
AI(myProxy);
Most commonly methods do not change any values outside of their method scope, instead they return a new value. Only methods that accept the parameter by reference instead of value can change the value of the parameter in the calling context.
This article on MSDN is a great starting point for understanding how to pass parameters by reference instead of value.
Please note that you will not be able to pass a class member as a ref or out parameter. If you wish to update part of a class via reference, you will need to pass the entire class object as the reference.
What is value keyword here and how is it assigning the value to _num? I'm pretty confused, please give the description for the following code.
private int _num;
public int num
{
get
{
return _num;
}
set
{
_num=value;
}
}
public void button1_click(object sender,EventArgs e)
{
num = numericupdown.Value;
}
In the context of a property setter, the value keyword represents the value being assigned to the property. It's actually an implicit parameter of the set accessor, as if it was declared like this:
private int _num
public int num
{
get
{
return _num;
}
set(int value)
{
_num=value;
}
}
Property accessors are actually methods equivalent to those:
public int get_num()
{
return _num;
}
public void set_num(int value)
{
_num = value;
}
The value keyword is a contextual keyword, that is, it has a different meaning based on its context.
Inside a set block, it simply means the value that the programmer has set it to. For instance,
className.num = 5;
In this case, value would be equal to 5 inside of the set block. So you could write:
set
{
int temp = value; //temp = 5
if (temp == 5) //true
{
//do stuff
}
_num = value;
}
Outside of a set block, you can use value as a variable identifier, as such:
int value = 5;
Note that you cannot do this inside a set block.
Side note: You should capitalize the property num to Num; this is a common convention that makes it easier for someone who's reading your class to identify public and private properties.
Properties are the way you can READ, WRITE or COMPUTE values of a private field or class variable.
The set or setter inside a property is used when the code assigns a value into the private field or (class) variable.
The value keyword means simply "the thing that is being assigned".
public class StaffMember
{
private int ageValue;
public int Age
{
set
{
if ( (value > 0) && (value < 120) )
{ this.ageValue = value; }
}
get {
return this.ageValue;
}
}
}
//Rob Miles - C# Programming Yellow Book