I have many constants I need to move around in one of my classes but I'm not allowed to use member variables. What are some options?
Here's my initial try:
private void MyConstants(out int textSize, out int paddingValue, out int borderType, ...)
{
//Set them here
}
private Method1()
{
int textSize = 0;
int paddingValue = 0;
int borderValue = 0;
....
MyConstants(out textSize, out paddingValue, out borderValue)
}
private Method2()
{
int textSize = 0;
int paddingValue = 0;
int borderValue = 0;
....
MyConstants(out textSize, out paddingValue, out borderValue)
}
//Many more methods...Just seems to repetitive.
Use Private Class or Struct.
private class Variables {
public int textSize;
public int paddingValue;
public int borderValue;
}
private Variables MyConstants{
get{ return new Variables(){textSize=1, paddingValue=2, borderValue=3};}
}
If you need to initialize in constructor try using readonly instead on const.
Edit 1:
You can create a class that holds a private Dictionary:like key and value.
put a "object LoadConstant(string)" method in it that will withdraw the data.
public static class ConstantManager {
private static Hashtable _consts = new Hashtable();
private static const keyName = "Name 1";
public static void ConstantManager()
{
_consts[keyName] = ...;
}
public static Hashtable GetConstants()
{
var _copy = new Hashtable(_consts);
return _copy;
}
}
public OtherClass{
public void Method()
{
var consts = ConstantManager.GetConstants();
var a = consts[ConstantManager.keyName];
}
}
Related
Thanks to the kind folks who answered my previous question from a few days ago, I now know how to pass arguments by reference:
static void Main()
{
int i = 0;
Add(ref i, 100);
// now i == 100
}
static void Add(ref int arg, int increment)
{
arg += increment;
}
But is there a way for me not to just pass i by reference, but actually store its location in another variable? By that I mean use i like I did in my example; affecting the original instance, but in a way that's permanently linked and not leaving scope.
I vaguely know that I could use a pointer to determine the location in unsafe context but I was wondering if I could do this without any of that, or if it is just recommended to use the unsafe method.
If you are using C# 7 you can use ref local and ref return to store an updateable reference to any field.
In this example I change the private field _privateField from 0 to 100 from outside Foo, the class in which it is defined, by returning it as a ref int and updating it by reference.
class Foo
{
private int _privateField = 0;
public ref int GetReference()
{
return ref _privateField;
}
public override string ToString()
{
return _privateField.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField = 100;
Console.WriteLine(foo);
}
}
Prior to that, you'd have to store the value in a field contained in an object, and pass around a reference to the object instead.
In this example I change the value from 0 to 100 from outside Foo, even though it is stored (indirectly) in a field that is private inside the Foo instance.
class ValueTypeReference<T> where T : struct
{
public T Value { get; set; }
}
class Foo
{
private ValueTypeReference<int> _privateField = new ValueTypeReference<int>{ Value = 0 };
public ValueTypeReference<int> GetReference()
{
return _privateField;
}
public override string ToString()
{
return _privateField.Value.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField.Value = 100;
Console.WriteLine(foo);
}
}
Output:
100
Well, if I udnerstood you correctly, you want the variable to have global scope, which can be achieved by putting variable as class field/property:
class Program
{
private static int _i;
static void Main()
{
_i = 0;
Add(100);
// now _i == 100
}
static void Add(int increment)
{
_i += 100;
}
}
I have created a class that looks similar to the one below. As you can see I created a few constructors that I am trying to chain using : this()
class RTTutils
{
#region Variables
private bool verbose = false;
private bool canWrite = false;
private int x;
private int y;
public RTTutils()
{
x = 5;
y = 5;
RTTCalc();
}
public RTTutils(int samples, bool verbose) : this()
{
this.verbose = verbose;
this.samples = samples;
}
public RTTutils(int samples, bool verbose, bool canWrite) : this()
{
this.verbose = verbose;
this.samples = samples;
this.canWrite = canWrite;
}
public RTTutils(int samples) : this(samples, false, false)
{
}
public RTTutils(bool verbose) : this()
{
this.verbose = verbose;
}
private void RTTCalc()
{
if (this.verbose)
Console.WriteLine("Test");
}
I am trying to initialize it using
RTTutils rttcalculator = new RTTutils(true);
or any other combination for verbose and canWrite, they still remain false though. As an example in this case we will see nothing printed in the console, even though I indicated true when initializing the class.
What am I doing wrong in this case?
You expect (wrongly) boolean class fields used in method RTTCalc to have values you set in constructors with parameters. However, the parameterless constructor executes before these assignments.
Do not call RTTCalc in parameterless constructor. Provide static factory methods instead:
class RTTutils
{
private bool verbose = false;
private bool canWrite = false;
private RTTutils()
{
sampleList.Add(100); // First sample should be 100
optionChosen.Add("E");
x = 5;
y = 5;
System.IO.File.Delete(this.path);
}
private RTTutils(bool verbose) : this()
{
this.verbose = verbose;
}
private void RTTCalc()
{
if (this.verbose)
Console.WriteLine("Test");
}
public static RTTutils Create(bool verbose)
{
RTTutils result = new RTTutils(verbose);
result.RTTCalc();
return result;
}
}
Given your code above, I rewrote it and it initializes verbose and canWrite as expected.
class Foo
{
private bool _verbose = false;
private bool _canWrite = false;
private int _samples;
private int x;
private int y;
public Foo(int samples, bool verbose, bool canWrite)
{
_verbose = verbose;
_canWrite = canWrite;
_samples = samples;
x = 5;
y = 5;
RTTCalc();
}
public Foo() : this(0, false, false) { }
public Foo(int samples) : this(samples, false, false) { }
public Foo(int samples, bool verbose) : this(samples, verbose, false) { }
private void RTTCalc()
{
Console.WriteLine($"V={_verbose}, S={_canWrite}");
Console.ReadKey();
}
}
class Program
{
static void Main(string[] args)
{
Foo test1 = new Foo(1, true, false);
Foo test2 = new Foo(1, true);
Foo test3 = new Foo();
}
}
Does this work for you? If not then you are doing something else that is not shown in your code that is affecting verbose and canWrite.
I have to create a program where the player has 6 choices, between 2 pets, he must decide either to feed, talk or play with each one, however he can only do one at a time and each time he chooses an option the option chosen (except when talking) makes the other options increase while the former one decreases.
Im having trouble in all aspects, inside the program and inside the class.
I can't seem to define the random numbers inside the Class, and that makes the program not work.
This is the code for the Class so far, here is where the problem must be happening:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tamagochi
{
class Tamagochi
{
private string tamagochi;
private double hungerLvl;
private double boredomLvl;
private double totalLevels;
private static int time;
private static int RandomNumberGenerator;
private static int ranNum1;
private static int ranNum2;
private static int ranNum3;
private static int ranNum4;
public Tamagochi (string tamagochi)
{
this.tamagochi = tamagochi;
}
public Tamagochi (string tamagochi, double hungerLvl, double boredomLvl, double randomNumbers, int RandomNumberGenerator)
{
this.tamagochi = tamagochi;
this.hungerLvl = hungerLvl;
this.boredomLvl = boredomLvl;
this.RandomNumberGenerator = RandomNumberGenerator;
}
public static void IncreaseTime()
{
++time;
}
public static void IncreaseBoredomLvl(double boredomLvl, int random)
{
boredomLvl += // randomnumber
}
public static void IncreaseHungerLvl(double hungerLvl)
{
hungerLvl += //randomnumber
}
public static void randomNumber(int min, int max)
{
Random RandomNumberGenerator = new Random();
ranNum1 = RandomNumberGenerator.Next(1, 6);
ranNum2 = RandomNumberGenerator.Next(1, 6);
ranNum3 = RandomNumberGenerator.Next(1, 6);
ranNum4 = RandomNumberGenerator.Next(1, 6);
}
//return section
public string GetTamagochi()
{
return tamagochi;
}
public double GetBoredomLvl()
{
return boredomLvl;
}
public double GetHungerLvl()
{
return hungerLvl;
}
public static int GetTime()
{
return time;
}
public static int GetRandomNum()
{
return ranNum1;
}
}
}
Any help on trying to make this work?
The Random number should be declared outside the function.
The seed should be effective.
If you want a number between 1 and 6 (both including) you should put in the Next() function from 1 to 7 (because 7 is not included)
So, Your code should look like this:
class Tamagochi
{
private int ranNum1;
private int ranNum2;
private int ranNum3;
private int ranNum4;
Random RandomNumberGenerator;
public Tamagochi()
{
RandomNumberGenerator = new Random(Guid.NewGuid().GetHashCode());
}
public void GetRandomNumber()
{
ranNum1 = RandomNumberGenerator.Next(1,7);
ranNum2 = RandomNumberGenerator.Next(1,7);
ranNum3 = RandomNumberGenerator.Next(1,7);
ranNum4 = RandomNumberGenerator.Next(1,7);
}
}
So I got this base class
abstract class Item
{
private int x, y, ataque, defesa, saude, raridade;
private char appearance;
private bool pickedUp;
private readonly Random rng = new Random();
public Item(Map argMap, int argAtaque, int argDefesa, int argSaude, int argRaridade, char argAppearance)
{
bool empty = false;
while (!empty)
{
x = rng.Next(1, argMap.ReLengthX() - 1);
y = rng.Next(1, argMap.ReLengthY() - 1);
if (!argMap.CheckTile(y, x)) empty = true;
}
pickedUp = false;
ataque = argAtaque;
defesa = argDefesa;
saude = argSaude;
raridade = argRaridade;
appearance = argAppearance;
}
}
And I got this derived class
class Armadura : Item
{
public Armadura(Map argMap, int ataque, int defesa, int saude, int raridade, char appearance) : base(argMap, ataque, defesa, saude, raridade, appearance)
{
ataque = -1;
defesa = 2;
saude = 0;
raridade = ReRNG().Next(Convert.ToInt32(Math.Round(argMap.ReLengthY() * 0.02)), Convert.ToInt32(Math.Round(argMap.ReLengthY() * 0.04)));
appearance = ' ';
}
}
So my question is, how do I get to set the values on :base, using the values that I set on the derived constructor (for example, set the base argAtaque with ataquewwww, therefore, argAtaque being equal to '-1')?
I tried this using a few ways but I didn't get this to work in any way.
I thank you in advance!
The : base() syntax will work for constants and parameters, but not for more complex expressions with side-effects (as you found).
You'll be needing a initialization method on the base class.
abstract class Item
{
...
// If you use this constructor, call Setup() afterwards.
public Item() {}
// Constructor including a call to Setup()
public Item(Map argMap, int argAtaque, int argDefesa, int argSaude, int argRaridade, char argAppearance)
{
Setup(argMap, argAtaque, argDefesa, argSaude, argRaridade, argAppearance);
}
// Sets private variables for this Item
protected void Setup(Map argMap, int argAtaque, int argDefesa, int argSaude, int argRaridade, char argAppearance)
{
bool empty = false;
while (!empty)
{
x = rng.Next(1, argMap.ReLengthX() - 1);
y = rng.Next(1, argMap.ReLengthY() - 1);
if (!argMap.CheckTile(y, x)) empty = true;
}
pickedUp = false;
ataque = argAtaque;
defesa = argDefesa;
saude = argSaude;
raridade = argRaridade;
appearance = argAppearance;
}
}
Now you can setup the base class with the calculated values:
class Armadura : Item
{
public Armadura(Map argMap)
{
int ataque = -1;
int defesa = 2;
int saude = 0;
int raridade = ReRNG().Next(Convert.ToInt32(Math.Round(argMap.ReLengthY() * 0.02)), Convert.ToInt32(Math.Round(argMap.ReLengthY() * 0.04)));
char appearance = ' ';
Setup(argMap, ataque, defesa, saude, raridade, appearance);
}
All you have to do is set ataque in the child constructor, as it will override what ataque is being set to in your base class. The base constructor is called first, then the child constructor.
For this to work, you will need to make your private variables protected in the base class. This will make them private in the child class.
class SomeClass
{
private struct PhraseInfo
{
public int Start;
public int Length;
}
...
private void SomeMethod(...)
{
List<PhraseInfo> posesBracket = new List<PhraseInfo>();
posesBracket.Add(new PhraseInfo());
posesBracket[0].Start = 10;
}
of cause, posesBracket[0].start=10; occur compiler error CS1612 : "Cannot modify the return value of 'expression' because it is not a variable"
how can i modify a value in list?
The problem is that PhraseInfo is a value type, so the this[] method will return a value, not a reference, to solve it, do this:
PhraseInfo pi = posesBracket[0];
pi.Start = 10;
posesBracket[0] = pi;
var temp = posesBracket[0];
temp.Start = 10;
posesBracket[0] = temp;
You cannot have a struct defined as a method. And as they say, you need the reference to change values. So it goes like this:
class SomeClass
{
private struct PhraseInfo
{
public int Start;
public int Length;
}
private void somemethod()
{
List<PhraseInfo> posesBracket = new List<PhraseInfo>();
posesBracket.Add(new PhraseInfo());
PhraseInfo pi = posesBracket[0];
pi.Start = 10;
posesBracket[0] = pi;
}
}