This question already has answers here:
Check inside method whether some optional argument was passed
(10 answers)
Closed 2 years ago.
I hope someone can help me or give me an information if that is even possible...
I want to check in an Named-Method which parameters are really set and passed to it.
It would be possible to make an Dictionary and pass the parameter by an KeyValue-Pair to the Method, but is there an other solution?
Can i check the current method in the stack-trace and collect the current set argmuents of that method or something?
For better understanding, i created an example to visualize the issue:
class Program
{
static void Main(string[] args)
{
TestClass newC = new TestClass("Init", 10);
newC.ToString(); //{varStr: "Init"; varInt: 10}
newC.update(vStr: "ok");
newC.ToString(); //{varStr: "ok"; varInt: 0}
// !!! but should have {varStr: "ok"; varInt: 10} !!!
Console.WriteLine("<-- press any key to exit -->");
Console.ReadKey();
}
}
class TestClass
{
string varStr;
int varInt;
public TestClass(string vStr, int vInt)
{
varStr = vStr;
varInt = vInt;
}
public void update(string vStr = default, int vInt = default)
{
//here check it if vStr-Param was set and set varStr only if it was passed to it!
//TODO
varStr = vStr;
//here check it if vInt-Param was set and set varInt only if it was passed to it!
//TODO
varInt = vInt;
}
public override string ToString()
{
Console.WriteLine($"TestClass: varStr: {varStr}; varInt: {varInt};");
return null;
}
}
Is there any way to achieve this, like the way i think?
EDIT:
Use default value and check it!
The default value can also be set over this Method! So an solution
with checking the default value and only if that is equal than we set
the value, is no option for us.
We have also an "custom-class" which we give over that method and it
could also be nullable.
Use Overload methods!
The Problem is that this class has not 2 variables, it has over 15 and
it would be an big overhead to write each overload method.
SOLUTION:
I found a Solution without declare default values... so every Value is able to be set!
class TestClass
{
string varStr;
int varInt;
TestClass1 varCustomClass;
public TestClass(string vStr, int vInt, TestClass1 vCustomClass)
{
varStr = vStr;
varInt = vInt;
varCustomClass = vCustomClass;
}
public void update(Opt<int> varInt = default(Opt<int>),
Opt<string> varStr = default(Opt<string>),
Opt<TestClass1> varCustomClass = default(Opt<TestClass1>))
{
if (varStr.HasValue)
{
this.varStr = varStr.Value;
}
if (varInt.HasValue)
{
this.varInt = varInt.Value;
}
if (varCustomClass.HasValue)
{
this.varCustomClass = varCustomClass.Value;
}
}
public override string ToString()
{
Console.WriteLine($"TestClass3: varStr: {varStr}; varInt: {varInt}; varCustomClass: {varCustomClass};");
return null;
}
}
public struct Opt<T>
{
public Opt(T value)
{
_value = value;
_hasValue = true;
}
public static explicit operator T(Opt<T> optional)
{
return optional._value;
}
public static implicit operator Opt<T>(T value)
{
return new Opt<T>(value);
}
T _value;
public T Value
{
get { return _value; }
}
bool _hasValue;
public bool HasValue
{
get { return _hasValue; }
}
}
Might your string also be null? If not, you can check if it's null. For your int, you can use a nullable value type:
public void update(string vStr = null, int? vInt = null)
{
if(vStr != null)
{
varStr = vStr;
}
if(vInt != null)
{
varInt = vInt.Value;
}
}
If you have only a few parameters and they all have different types, overloaded methods are also a good solution:
public void update(string vStr)
{
varStr = vStr;
}
public void update(int vInt)
{
varInt = vInt;
}
public void update(string vStr, int vInt)
{
update(vStr);
update(vInt);
}
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 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.
This question already has answers here:
What is the { get; set; } syntax in C#?
(20 answers)
Closed 7 years ago.
I have an strange comportement with my singleton class.
public class HttpCommunicator{
public const int TYPEJSON = 1;
private static HttpCommunicator;
private bool TypeIsInit = false;
public static HttpCommunicator Instance {
get{
if( instance == null ){
instance = new HttpCommunication();
}
return instance;
}
}
private HttpCommunicator(){}
public int RequestType {get {return RequestType;} set{ this.RequestType = value; TypeIsInit = true;}
}
And later in another class i call this
HttpComminicator.Instance.RequestType = HttpCommunicator.TYPEJSON;
My app get stuck/freeze and my debugger don't show me any error. But if I change the get;set; method for this attribut to:
public int GetRequestType(){
return RequestType;
}
public void SetRequestType(int value){
RequestType = value;
TypeIsInit = true;
}
everything works like a charm.
Anybody can explain me why I get this?
Check out your property:
public int RequestType
{
get { return RequestType; }
set { this.RequestType = value; TypeIsInit = true; }
}
You have a bunch of problems here.
What happens when you get that property?
RequestType.get is going to execute, which in turn is going to return RequestType;. To return RequestType you must read RequestType, which will trigger RequestType.get and the loop will go on and on and on and on.
My point is that you're trying to return a property by returning said property, which will probably end up causing a StackOverflowException.
The same can be said about your set accessor.
To fix this, have private fields behind the scenes:
private int _requestType;
public int RequestType
{
get { return _requestType; }
set { _requestType = value; TypeIsInit = true; }
}
This question already has answers here:
Overloading getter and setter causes a stack overflow in C# [duplicate]
(4 answers)
Closed 3 years ago.
class Program
{
static void Main(string[] args)
{
something s = new something();
s.DoIt(10);
Console.Write(s.testCount);
}
}
class something
{
public int testCount
{
get { return testCount; }
set { testCount = value + 13; }
}
public void DoIt(int val)
{
testCount = val;
}
}
Is what I have, because I was wanting to test and play around with the getters/setters stuff for C#. However, I get a StackOverFlowException was unhandled at "set { testCount = value + 13}". And I can't step through it, as I get a "The debugger cannot continue running the process. Process was terminated" message from Visual Studio. Any ideas what I'm doing wrong?
Edit: Today I've learned that I've done a pretty stupid derp. Given the multitudes of instant responses. Now I know better.
You have an infinite recursion, as you are referring to the property in the property.
You should use a backing field for this:
private int testCount;
public int TestCount
{
get { return testCount; }
set { testCount = value + 13; }
}
Note the property name TestCount (which also conforms to C# naming standard), as opposed to the field name testCount (lowercase t).
You should declare a variable to back the property:
class something
{
private int _testCount;
public int testCount
{
get { return _testCount; }
set { _testCount = value + 13; }
}
...
You have a circular reference in your property's getter. Try this:
class Something
{
private int _testCount;
public int TestCount
{
get { return _testCount; }
set { _testCount = value; }
}
public void DoIt(int val)
{
_testCount = val;
}
}
This:
public int testCount
{
get { return testCount; }
it returns itself, which causes it to execute itself.
Instead of return the own property in itself, store the intended value in another (preferably protected or private) variable. Then manipulate that variable both in the setter and in the getter.
class Program
{
static void Main(string[] args)
{
something s = new something();
s.DoIt(10);
Console.Write(s.testCount);
}
}
class something
{
private int _testCount;
public int testCount
{
// you are calling the property within the property which would be why you have a stack overflow.
get { return _testCount; }
set { _testCount = value + 13; }
}
public void DoIt(int val)
{
testCount = val;
}
}