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.
Related
I've got a small project where I would like to avoid creating a setter for each integer.
So I'm thinking if it's even possible.
So I would like to set an amount of
player.setResource(player.money, 100);,
player.setResource(player.coal, 20);,
etc.
I'm not sure first of all if it's possible, and second of all how to write a function itself.
public void setResource(int resource, int amount)
{
???
}
Use an enum for this. Define an enum in your project like so
public enum ResourceType { Coal = 0, Money = 1, Health = 2 }
Now, you can add a switch case in your setResource function to check what enum you've passed, and set the corresponding value. This is however assuming all your values are integers. you can make a separate one for floats, or just use floats for everything, upto you.
This will be your new SetResource Function, assuming you have a reference to your player.
public void setResource(ResourceType resource, int amount)
{
switch(resource)
{
case ResourceType.Money:
player.money = amount;
break;
case ResourceType.Coal:
player.coal = amount;
break;
}
}
You can use an Enum to define the resources types and a Dictionary to store the values of each resource. Here's an example:
public enum ResourceType
{
Coal,
Money
}
private Dictionary<ResourceType, int> _resources = new Dictionary<ResourceType, int>();
public void SetResource(ResourceType resourceType, int value)
{
_resources[resourceType] = value;
}
public int GetResource(ResourceType resourceType, int defaultValue = 0)
{
if (_resources.TryGetValue(resourceType, out var value))
return value;
else
return defaultValue;
}
public class Player
{
public int money { get; set; }
public int coal { get; set; }
public void setResource(string resource, int amount)
{
this.GetType().GetProperty(resource).SetValue(this, amount);
}
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Player player = new Player();
player.setResource(nameof(player.coal), 4);
}
}
In your method, the target is not passed, the value of the integer is assigned to a local variable resource that only exists within the method.money and coal are not affected.
You need to pass the address of those data.
public void setResource(ref int resource, int amout)
{
resource = amount;
}
player.setResource(ref player.coal, 100);
If nothing else happens in the method, a get/set property would do the same.
There are multiple ways how you could do this.
I often use this aproach for quick prototyping.
First you create two variables for the data you want to assing, then you create a Setter function and with this you can set variables through other scripts.
int value 1;
int value 2;
public void SetData(int value1, int value2)
{
this.value1 = value1;
this.value2 = value2;
}
The same aproach can be used for other data types, you just need to create the variables.
i.e.
MyClass myClass = new MyClass() { Value = 5 };
I have a bunch of constructor calls like the one above, but now I've realized I need to add logic to the constructor, which was a massive oversight. Currently I have no constructor, so just a blank implicit default constructor.
The below code should explain my problem.
Edit: I'm not actually doing validation, that's just a simple example of constructor logic
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new Test(1) + " should be true");
Console.WriteLine(new Test(0) + " should be false");
Test test = new Test(0) { Value = 1 }; // It allows this syntax, oddly, but the value that's used is the one passed as a parameter
Console.WriteLine("I wish " + test + " was true");
// This is what I have currently, but I'd like to add logic like that which exists in the parameterized constructor
//Test test = new Test() { Value = 1 } // Would ideally function just like Test(1), otherwise I have to go and change every call
// OUTPUT
// True should be true
// False should be false
// I wish False was true
Console.ReadLine();
}
}
class Test
{
public bool? IsGood { get; }
public int Value { get; set; }
// This doesn't currently exist in my class, but I'd like to add it
public Test(int value)
{
if (value == 1)
IsGood = true;
else
IsGood = false;
}
public override string ToString()
{
return IsGood.ToString();
}
}
Don't write code like this in the first place.
I'd write your code like this:
class Test
{
public static bool IsValid(int value)
{
return whatever; // test for validity here
}
public int Value { get; private set; } // Don't let anyone change it.
public Test(int value) {
if (!IsValid(value)) throw new InvalidArgumentException("value");
this.Value = value;
}
}
There, now Value is always valid; the user can know ahead of time whether it is valid or not; an attempt to set an invalid value produces an exception. This assumes that Value cannot change.
If Value can change then write it like this:
class Test
{
public static bool IsValid(int value)
{
return whatever; // test for validity here
}
private int value;
public int Value { get { return value; }
set
{
if (!IsValid(value)) throw new InvalidArgumentException("value");
this.value = value;
}
}
public Test(int value) {
this.Value = value;
}
}
Now the value is again always legal.
If it is legal for value to be invalid, then:
class Test
{
public bool IsValid
{
get
{
return whatever; // test for validity here
} // read-only property
}
public int Value { get; set; }
public Test(int value) {
this.Value = value;
}
}
Now the value can be any integer and whether it is valid or not can be tested dynamically.
Can I set members outside of a constructor while still using logic in the constructor?
Meaning, what, exactly?
Using the object initializer syntax, a constructor still runs. You may even choose which one to use, through the normal constructor overload syntax (which you seem to show, but you say it's not in your class?). The code in your constructor looks at the parameter value that is passed to it, not the property Value (which it doesn't even set). But if you meant for the two to work together, then sure…you can set the property in the constructor and set IsGood in the Value property setter.
If you're going to do it that way, then I would not bother with the logic in the constructor at all. Just set the Value property and let its setter do the rest of the work:
class Test
{
public bool? IsGood { get; private set; }
private int _value;
public int Value
{
get { return _value; }
set
{
_value = value;
IsGood = _value == 1;
}
}
public Test(int value)
{
Value = value;
}
}
I should point out that the semantics of the above is slightly different from what you seem to have started with. That is, the Value property is not read-only, and so can be set at any time. So, similarly, the IsGood property can change at any time. You previously had declared it as read-only and it was settable only in the constructor.
It's not clear from your question whether that's a problem or not. If you want IsGood to be strictly read-only (i.e. without even a private setter), then it won't be possible to do literally what you're asking for, because in the object initializer syntax, it relies on setting member properties after the constructor has already returned.
For the moment, I'll assume it's not a problem to add the private setter to the IsGood property.
Note that since IsGood apparently depends solely on the value of Value, you could even implement the above like this:
class Test
{
public bool? IsGood => _value != null ? _value == 1 : (bool?)null;
private int? _value;
public int Value
{
get { return _value ?? 0; }
set { _value = value; }
}
public Test(int value)
{
Value = value;
}
}
That is, don't even bother storing a value for IsGood. Just return the appropriate value based on the current state of the Value property (null if it's never been set, true if it's currently set to 1, and false otherwise).
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;
}
}
I have a class with 5-6 fields that should be initialized once after the constructor runs.
public OriginalFileProcessor(IConfigManager configManager)
{
this._configManager = configManager;
this._field1 = this._configManager.GetAppSetting<int>ConfigKeys.Key1);
this._field2 = this._configManager.GetAppSetting<int>ConfigKeys.Key2);
this._field3 = this._configManager.GetAppSetting<int>ConfigKeys.Key3);
this._field4 = this._configManager.GetAppSetting<int>ConfigKeys.Key4);
this._field5 = this._configManager.GetAppSetting<int>ConfigKeys.Key5);
}
But I don't like to write logic apart from just simple assignments in the constructor.
I can't use inline initialization for field1 for example since then I can't use the _configManager instance there:
private int readonly _field1 = this._configManager.GetAppSetting<int>ConfigKeys.Key1);
If I use a readonly property then I'd have to add extra code like this:
private int? _field1;
public int Property1
{
get
{
if (!this._field1.HasValue)
{
this.__field1 = this._configManager.GetAppSetting<int>(Key1);
}
return this._field1.Value;
}
}
Is there any simpler approach for late initialization of instance fields?
Lazy<T> is a good option as suggested.
What I usually use is the following...
Providing your _field* is a nullable
In your property you can do...
return this.__field1 ?? (this.__field1 = this._configManager.GetAppSetting<int>(Key1));
EDIT:
Given comments discussion - why not just use a non static approach over Lazy<T>, e.g.
private readonly Lazy<int?> _field;
// init in ctor
_field = new Lazy<int?>(() => YourFieldInit(""));
// use in property
return _field.Value ?? 0;
EDIT 2:
And a small test to clarify the Lazy behavior:
public class DoLazy
{
Lazy<int?> _field;
public DoLazy()
{
// 'lazy' gets initialized - but `YourFieldInit` is not called yet.
_field = new Lazy<int?>(() => YourFieldInit(""));
}
int Property
{
get
{
// `YourFieldInit` is called here, first time.
return _field.Value ?? 0;
}
}
int? YourFieldInit(string test)
{ // breakpoint here
return -1;
}
public static void Test()
{
var lazy = new DoLazy();
int val1 = lazy.Property;
var val = lazy.Property;
}
}
Put a breakpoint inside the YourFieldInit - to see when it's actually called.
Call DoLazy.Test() from your e.g. Main.
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