How to control the maximum value of variables? - c#

As the title says, I would like to set the maximum value of the skill, stam and luck integers to the value of the related *Max integers. The *Max int values are set randomly during the start up of the program and the regular values are changed throughout the running of the program. There may be a few instances where the *Max value gets increased or decreased during play.
public static int skillMax = 0;
public static int stamMax = 0;
public static int luckMax = 0;
public static int skill = skillMax;
public static int stam = stamMax;
public static int luck = luckMax;
As my knowledge of C# is still in its infancy, I have not tried much. However I have searched far and wide on the internet however and not been able to find anything except for the MinValue and MaxValue fields and this piece of code with no explanation:
protected int m_cans;
public int Cans
{
get { return m_cans; }
set {
m_cans = Math.Min(value, 10);
}
}
Thanks in advance for any advice you throw my way!

Explanation for the code: Cans is a property. Properties provide controlled access to class or struct fields (variables). They consist of two methods called get to return a value and set to assign the value. A property can also have only a getter or only a setter.
The property Cans stores its value in a so called backing field. Here m_cans. The setter gets the new value through the keyword value.
Math.Min(value, 10) returns the minimum of the two parameters. I.e., for example, if value is 8, then 8 is assigned to m_cans. If value is 12, then 10 is assigned to m_cans.
You can use this property like this
var obj = new MyCalss(); // Replace by your real class or struct name.
obj.Cans = 20; // Calls the setter with `value` = 20.
int x = obj.Cans; // Calls the getter and returns 10;
Properties help to implement the principle of Information hiding.
You can easily adapt this example your variables. Often class level variables (fields) are prepended with _ to differentiate them from local variables, i.e. variables declared in methods. Properties are written in PascalCase.
private static int _skillMax; // Fields are automatically initialized to the default
// value of their type. For `int` this is `0`.
public static int SkillMax
{
get { return _skillMax; }
set {
_skillMax = value;
_skill = _skillMax; // Automatically initializes the initial value of Skill.
// At program start up you only need to set `SkillMax`.
}
}
private static int _skill;
public static int Skill
{
get { return _skill; }
set { _skill = Math.Min(value, _skillMax); }
}

Create methods to update values
private static void UpdateSkill(int newValue)
{
skill = newValue;
skillMax = newValue > skillMax ? newValue : skillMax;
}

Related

How to pass a Setter to a constructor

given the following:
public class ClassA
{
private int val;
public int setter1 { set{ val = value * 100 }}
public int setter2 { set{ val = value * 200 }}
}
public class ClassB
{
public int setter;
public ClassB(int someSetter)
{
b = someSetter; // Obviously impossible, it's merely for demonstration purposes
}
}
Would it be possible to assign Getter/Setters to instances that belong to a different class?
So that when we create 2 instances:
B b1 = new B(setter1),
b2 = new B(setter2);
b1.setter = 1; // 'val' is equal to 100
b2.setter = 2; // 'val' is equal to 400
The reason I need this:
I have a bunch of instances that belong to the same class, and a local variable which I assign data to.
I don't know which instance I'm accessing, but I want to assign a Setter so that the value of the local variable changes.
I can easily achieve this differently, but I was wondering if passing Setters was possible.
Thx for reading!

In C# set value to a constant property

I am partly modifying an application where I will need to set value of the following constant to the value of the environment variable if exists.
What I already have:
private const string BuildPackagePath = #"\\server\build\";
What I would like to do is:
if (Environment.GetEnvironmentVariable("EnvVar") != null)
Set the property value to = Environment.GetEnvironmentVariable("EnvVar")
else
{Keep default/assigned value}
I understand that the left side of an asignment has to be a variable. I will probably have to change the type but was just wondering if anyone could give me an idea so the structure of current code can be kept as is.
consider using a static property without setter
// evaluates Environment Variable on each call
private static string BuildPackagePath
{
get { return Environment.GetEnvironmentVariable("EnvVar") ?? #"\server\build\"; }
}
static readonly field will evaluate Environment Variable only once (but not immediately at startup When do static variables get initialized in C#?)
private static readonly string BuildPackagePath =
Environment.GetEnvironmentVariable("EnvVar") ?? #"\server\build\";
You can´t modify a constants value, that´s why it´s called constant. However you can use readonly to indicate that the member can be modified only within the constructor:
class MyClass
{
private readonly string BuildPackagePath;
public MyClass()
{
var value = Environment.GetEnvironmentVariable("EnvVar");
if(value != null) this.BuildPackagePath = value;
else this.BuildPackagePath = #"\server\build\";
}
}
Or even shorter using the null-conitional operation:
this.BuildPackagePath = value ?? #"\server\build\";
You can use "readonly" modifier instead of const. Then you can set a value of the field in a constructor of a class. For example:
class SampleClass
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SampleClass()
{
// Initialize a readonly instance field
z = 24;
}
}

By what logic, should instance constructors have access to static fields

I was wondering why do instance constructor have access to static fields? If I initialize static fields via static constructors, and by mistake again initialize them through instance constructors, then the second initialization overwrites the first one. What is the idea behind making them accessible through instance constructors? (Please have a look at the simple program below to understand my point)
using System;
class Program
{
static void Main()
{
Circle C1 = new Circle(5);
Console.WriteLine("The area of the first circle is {0}", C1.CalculateArea());
}
}
class Circle
{
public static float _Pi; // Since the value of pi will not change according to circles, we have to make it static
int _Radius; // This is an instance field, whose value is different for different instances of the class
static Circle() // A static constructor initializes the static fields
{
Console.WriteLine("Static constructor executed");
Circle._Pi = 3.14F;
}
public Circle(int Radius) // An instance constructor initializes the instance fields
{
Console.WriteLine("Instance constructor executed");
this._Radius = Radius;
Circle._Pi = 2.12F; // This again initializes the value of the pi to a different value as given by the static constructor
}
public float CalculateArea()
{
return this._Radius*this._Radius*Circle._Pi;
}
}
As an example of a use case where a constructor could want access to static members is when a static field contains a counter of instances for a class. You may want a class member to get, retain (in a non-static field), and increment this counter which would be static. Any time in the future that instance will have its own unique identifier.
Example:
public class Employee {
static int NextEmployeeId; // a counter across all employees
public int EmployeeId; // this instance's employee id
public string Name; // this instance's name.
static Employee() {
Employee.NextEmployeeId = 1; // first employee gets 1.
}
public Employee(string Name) {
this.Name = Name;
this.EmployeeId = Employee.NextEmployeeId++; // take an id and increment for the next employee
}
}
Static fields are accessible from everywhere, even from constructor, or even from Main/other class. The purpose is that you will have only one static property/ field singleton for the whole app.
public class AClass()
{
public static float staticField;
public float field;
public AClass()
{
staticField = 5;
field = 6;
}
static AClass()
{
staticField = 7;
}
}
public int Main()
{
float initially = AClass.staticField; // initially this staticField is 7.
AClass aclass = new AClass(); // instantiating AClass
float localfield = aclass.field; // this field does not affect anyone. It is 6
float newStaticField = AClass.staticField; // Due to previous instantiation, the value is now 5.
}
And I agree with you that in your example it is bad. Why? Because why would you change the value of Pi, since it is already determined and fixed, there is no reason to change the value of Pi in the constructor.
You probably need to know how to design class and get to know why you want to have the static field in the first place. Here is an example of a class which does it correctly having a static field (sort of... for example, because the Key should be hidden supposedly. This is just to show you how static field is useful and ok.):
public class NewEncryptionClass()
{
public static string Key;
public NewEncryptionClass()
{
}
public NewEncryptionClass(string newKey)
{
Key = newKey; // store the key and keep it forever
}
static NewEncryptionClass()
{
Key = "key1"; // initially key is "key1"
}
public string Encrypt(string str)
{
string result = string.Empty;
result = "adlasdjalskd" + Key + "ajlajfalkjfa" + str; // do the Encryption, I just made up
return result
}
}
Here, the purpose is that if you instantiate a NewEncryptionClass, you would want to save the key, so that the next time you do the encryption, you would always use the latest key without having to specify it everytime. For ex:
public int Main()
{
string initialkey = NewEncryptionClass.Key;
string result1 = new EncryptionClass().Encrypt("encryptThis"); // using key1
// let's change the key
string result2 = new EncryptionClass("key2").Encrypt("encryptThat"); // using key2
string result3 = new EncryptionClass().Encrypt("encryptOther"); // still using key2
}
This is of course if I want to keep the latest key forever, if not, then this class design is wrong and you need to rewrite it for your purpose.

Setting the value of a read only property in C#

I'm trying to make a mod for a game in c# and I'm wondering if there's a way to change the value of a read only property using reflections.
In general, no.
Three examples:
public int Value { get { return _value + 3; } } // No
public int Value { get { return 3; } } // No
public int Value { get; private set; } // Yes
So, you can change the value of the property while this property has corresponding private, protected or internal field.
Try this:
typeof(foo).GetField("bar", BindingFlags.Instance|BindingFlags.NonPublic).SetValue(foo,yourValue)
You can in both those scenarios:
readonly int value = 4;
and
int value {get; private set}
using
typeof(Foo)
.GetField("value", BindingFlags.Instance)
.SetValue(foo, 1000); // (the_object_you_want_to_modify, the_value_you_want_to_assign_to_it)
You cannot modify
int value { get { return 4; } }
though.
If it returns a calculated value like
int value { get { return _private_val + 10; } }
you would have to modify _private_val accordingly.
Yes, this is absolutely possible. Whether it is good practice or helpful to your purpose, I do not know. Going off of #ske57's great advice, here is a sample program that demonstrates reflection. The initial field value of 5 and the reflected field value of 75 are written to the console.
using System;
using System.Reflection;
namespace JazzyNamespace
{
class Program
{
static void Main()
{
var reflectionExample = new ReflectionExample();
// access the compiled value of our field
var initialValue = reflectionExample.fieldToTest;
// use reflection to access the readonly field
var field = typeof(ReflectionExample).GetField("fieldToTest", BindingFlags.Public | BindingFlags.Instance);
// set the field to a new value during
field.SetValue(reflectionExample, 75);
var reflectedValue = reflectionExample.fieldToTest;
// demonstrate the change
Console.WriteLine("The complied value is {0}", initialValue);
Console.WriteLine("The value changed is {0}", reflectedValue);
Console.ReadLine();
}
}
class ReflectionExample
{
public readonly int fieldToTest;
public ReflectionExample()
{
fieldToTest = 5;
}
}
}
As Mark said there could be scenarios where you cannot as . Think that the property itself could be a function derived from other properties, members.
However you may want to try the mechanisms explained here:
Is it possible to set private property via reflection?

Define maximum and minimum for fields in struct

I have a struct and an integer variable on it. My variable value must be between 1200 and 1599. but in default constructor I have no control in value of variable. How can I do this in my struct?
struct MyStruct
{
public int x;
public MyStruct(int x)
{
if(x>1599)
this.x=1599;
else if(x<1200)
this.x=1200;
else
this.x=x;
}
}
Another variant on using a property and a private backing field:
struct MyStruct
{
private int x;
public MyStruct(int x)
{
if (x > 1599)
this.x = 399;
else if (x < 1200)
this.x = 0;
else
this.x = x - 1200;
}
public int X { get { return x+1200; } }
}
Which ensures that the default constructed value is "in range".
But any variant is going to introduce some overhead, so it's up to you whether this is acceptable.
Use a property with a backing field:
struct MyStruct
{
private const int MIN_VALUE = 1200;
private const int MAX_VALUE = 1599;
private int x;
public int X
{
get { return x + MIN_VALUE; }
set
{
if(value > MAX_VALUE)
x = MAX_VALUE;
else if(value < MIN_VALUE)
x = MIN_VALUE;
else
x = value;
x -= MIN_VALUE;
}
}
// constructor is not really needed anymore, but can still be added
}
I combined the property with my setter and Damien_The_Unbeliever's getter to get the initial state of x right. I also agree with Tim about constants for the "magic numbers" and added that too. So please give this two also credit for "my answer".
Also as DatVM already said: Public fields/properties should start with a capital letter according to the common C# naming guidlines. This also enalbes you to use the same name for the backing field, but starting with a small letter (I personally do NOT like the ugly _)...
And last but not least: Please read rexcfnghk's answer, even if it is not really an answer, as he is also absolutely correct.
My variable value must be between 1200 and 1599
In C#, you cannot define your own default constructor for structs. If you have an array of MyStruct, like var myArray = new MyStruct[5], the default constructor of MyStruct will be invoked and elements in myArray will have all have x equals to 0, which is invalid according to your requirement.
Which is why I believe you have an incorrectly designed struct. According to the Framework Design Guidelines
√ DO ensure that a state where all instance data is set to zero, false, or null (as appropriate) is valid.
This prevents accidental creation of invalid instances when an array of the structs is created.
If you need argument validation when your struct's default constructor is invoked, use a class instead.
Also, your current design of MyStruct makes it mutable. please take a look on why Mutable structs are evil.
I would use properties with getter and setter and a private backing field where you can implement this logic or even throw an ArgumentOutOfRangeException if the value is outside of the boundaries.
Here is an example:
struct MyStruct
{
private const int MIN_VALUE = 1200;
private const int MAX_VALUE = 1599;
private int _X;
public int X
{
get { return _X; }
set { _X = checkBoundaries(value); }
}
private static int checkBoundaries(int x)
{
if (x > MAX_VALUE)
return MAX_VALUE;
else if (x < MIN_VALUE)
return MIN_VALUE;
else
return x;
}
public MyStruct(int x)
{
_X = checkBoundaries(x);
}
}
It's good practices to always use properties even if you don't need to restrict the access in the first place. Then it's easier to implement such a logic if you need.
One final note: i would suggest to use a class instead of struct.
You cannot define a default constructor in a struct, so you cannot prevent _X from being initialized with the default value 0.
You cannot initialze _X with the minimum value inline since that is also not allowed in structs
If your types are getting more comlex and you have rules like this it's a good indicator that a class would be more appropriate
You should change x into property instead:
private int _x;
public int x {
get
{
return _x;
}
set
{
_x = value;
if (_x > 1599)
{
_x = 1599
}
else if (_x < 1200)
{
_x = 1200
}
}
}
P.S: as for C# naming convention, it should be called X (capital) instead of x
A struct can be made to have a default value if, rather than using a public field, one uses a private field and a public property which transforms the field's value in such a way that its default value will map to the desired default for the structure. For example, you could have a backing field int _x_minus_1200; and have a property getter which returns _x_minus_1200 + 1200. I'm not hugely keen on such approaches (generally I prefer for structures to have public fields and behave like structures, and have the meaning and validation of structure fields be a function of the code that uses the structures) but in some cases they can be helpful.

Categories

Resources