Issues with readonly and private methods - c#

"Create a program named "DemoSquare" that initiates an array of 10 Square objects with sides that have values of 1 -10 and that displays the values for each square. The Square class contains fields for the area and the length of a side, and a constructor that requires a parameter for the area and the length of a side. The constructor assigns its parameter to the length of a Square's side and calls a private method that computes the area field. Also include read-only properties to get a Squares side and area."
Now I think that it is a trick question as I can't get the private method to compute the area because of the read-only assignment but here is my code:
class demoSquares
{
static void Main(string[] args)
{
Square[] squares = new Square[10];//Declares the array of the object type squares
for (int i = 0; i < 10; i++)
{
//Console.WriteLine("Enter the length");
//double temp = Convert.ToDouble(Console.ReadLine());
squares[i] = new Square(i+1);//Initializes the objects in the array
}
for (int i = 0; i < 10; i++)
{
Console.WriteLine(squares[i]);
}//end for loop, prints the squares
}//end main
}//end class
This is the Square Class:
public class Square
{
readonly double length;
readonly double area;
public Square(double lengths)//Constructor
{
length = lengths;
area = computeArea();
}
private double computeArea()//getmethod
{
double areaCalc = length * length;
return areaCalc;
}
}

Don't confuse read-only properties with read-only fields.
public class Square
{
public Square(double lengths)
{
Length = lengths;
Area = computeArea();
}
//Read only property for Length (privately settable)
public double Length {get; private set;}
//Read only property for Area (privately settable)
public double Area {get; private set;}
//Private method to compute area.
private double ComputeArea()
{
return Length * Length;
}
}

A read-only variable can indeed be assigned in the constructor, but not in methods called from the constrctor. There are ways to do that, i.e. : link. The correct way would be to calculate the area and store the result in the area variable.
I believe, though, that the meaning was different in the question. Quoting you :
Also include read-only properties to get a Squares side and area.
meaning, the question meant that you use Properties. Meaning, you would use private variables for length and area, and implement a get-only property for each :
public double Area
{
get
{
return area;
}
}

The question mentions readonly properties, not readonly fields.
a readonly field can only be assigned in a constructor or by a field initializer.
A readonly property can only be assigned inside the class.
public class Square
{
// Readonly field, can only be assigned in constructor or initializer
private readonly double _sideLength;
// Readonly property since it only contains a getter
public double SideLength { get { return _sideLength; } }
// Readonly property from outside the class since the setter is private
public double Area {get; private set;}
public Square( double sideLength )
{
_sideLength = sideLength;
CalcSquare();
}
private void CalcSquare()
{
this.Square = _sideLength * _sideLength;
}
}

Consider how you would restructure the code if you didn't try to assign the computed area to the area field, but instead returned the value from computeArea.
As an additional exercise, try making computeArea static and see how that affects the code.

You assignment never said your private function should assign area. It said the constructor should assign area with the result of a private method:
public class Square
{
private readonly double length;
private readonly double area;
public Square(double length)
{
this.length = length;
this.area = computeArea(length); // assignment of area in constructor!
}
private double ComputeArea(double length)
{
return length * length;
}
}

Related

Try to display a int through a static field, but return a weird value (C#)

I'm trying to cut down on how much duplication I have on my code, so I decided to make one of my classes a static class since I decided that its data should really be shared with everyone. Here's the static method below:
// A static class, that holds all object's coordinates, and methods to return & update their values.
internal static class Coordinate
{
private static int[,] PlayerCoordinate { get; set; }
public static int[,] GateCoordinate { get; }
public static int[,] FountainCoordinate { get; }
static Coordinate() // FIRST VALUE IS X (column), SECOND VALUE IS Y (row).
{
PlayerCoordinate = new int[,] { { 0, 0 } };
GateCoordinate = PlayerCoordinate; // Just starts off in the same place as player.
FountainCoordinate = new int[,] { { 2, 0 } };
}
// A static method, that sends the data of all object coordinates, deconstructed into seperate ints.
public static int PlayerColumn() { return PlayerCoordinate[0, 0]; }
public static int PlayerRow() { return PlayerCoordinate[0, 1]; }
public static int GateColumn() { return GateCoordinate[0, 0]; }
public static int GateRow() { return GateCoordinate[0, 1]; }
public static int FountainColumn() { return FountainCoordinate[0, 0]; }
public static int FountainRow() { return FountainCoordinate[0, 1]; }
// Updates the coordinates of the player.
public static void UpdatePlayerCoordinate(int column, int row) { PlayerCoordinate = new int[,] { { column, row } }; }
}
The main issue comes in from my GameManager class. On the console, the beginning section should print out "You are the room at (Column=0, Row=0), but it prints this instead:
Here is the code for my GameManager class:
internal class GameManager
{
private bool IsGameOver;
private Player Player;
private Updater Updater;
// Don't need to call Fountain or Coordinate since they're static
public GameManager()
{
IsGameOver = false;
Player = new();
Updater = new();
}
public void RunGame()
{
while (!IsGameOver)
{
Console.WriteLine("----------------------------------------------------------");
Updater.DisplayPlayerPosition(); // This is the main line that I'm having issues with as of right now. All other functions past this are another problem.
Updater.DisplayPlayerSenses();
string playerInput = Player.GetInput();
Updater.MovePlayer(playerInput);
IsGameOver = Updater.CheckForWin();
}
}
}
And just to make sure, here is the code from my updater class, with the specific method that I'm having issues with:
internal class Updater
{
// No fields
// Default constructor
// Gets the text to show the player his current position.
public void DisplayPlayerPosition() // This is the method that I'm having issues with.
{
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn}, Row={Coordinate.PlayerRow})");
}
...
I'm fairly new to the static keyword so I believe that I may be missing smth. I personally believe that it's because the class itself hasn't been initialized (like I haven't called the constructor for the Coordinate class, and apparently you can't call a static constructor anyways), but that's just me. If I could get any help, I'd greatly appreciate it!
PlayerColumn() and PlayerRow() are methods, but you are accesing them in the WriteLine statement as if they are properties.
Update your WriteLine to:
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn()}, Row={Coordinate.PlayerRow()})");

Assigning to a variable by reference?

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;
}
}

c# random numbers in abstract properties

How do I create an abstract property that can be a random number?
Parent.cs:
public abstract float ageInYears{get;}
Child.cs:
public override float ageInYears{
get{
return Random.Range(0, 10);
}
}
How do I ensure that Child.cs sets ageInYears to a random number, and that random number stays the same whenever accessed in the future?
private float? age;
public override float ageInYears{
get{
if(!age.HasValue) {
age = 10.0f * ((float) x.Next()) / ((float) int.MaxValue);
}
return age;
}
I use a method I call a Managed Entropy Source. Just a static class that creates a Random, then I call methods on MES, which being static, makes all random numbers come from the same 'stream', preventing the problem where 1000+ rng pulls can sometimes have just 2 values.
Also you can make nice wrappers, like CoinFlip() or Pick(list)
Helps when debugging random events, since you can swap out your MES implementation for a fake one that just reads from a file, or maybe inputbox's the number from the user ;)
An cryptographically seeded instance of Random is created per thread (inspired by this answer: https://stackoverflow.com/a/12952155/315689).
The backing property _ageInYears is initialized during the creation of each Child. Subsequent calls to the public ageInYears property will return the same value for a given instance of Child.
public class Child : Parent
{
[ThreadStatic]
private static Random _random;
private float _ageInYears;
public override float ageInYears { get { return _ageInYears; } }
public Child()
{
if (_random == null)
{
var cryptoResult = new byte[4];
new RNGCryptoServiceProvider().GetBytes(cryptoResult);
int seed = BitConverter.ToInt32(cryptoResult, 0);
_random = new Random(seed);
}
_ageInYears = (float)_random.NextDouble() * 10f;
}
}
https://dotnetfiddle.net/pmM5EC

Constructor not working as expected in Unity

I'm trying to create my GridData data in an Update/Awake function as a test. But I can't seem to get my constructor working. I'm new to CSharp and Unity. so, I'm a bit stuck here.
GridData Class
[System.Serializable]
public class GridData {
[System.Serializable]
public struct rowData{
public float[] colum;
}
public static int numRows =30;
public static int numColums =20;
public rowData[] rows = new rowData[numRows];
//
//Constructor
public GridData(int x, int y){
numRows =y;
numColums = x;
rowData[] rows = new rowData[numColums];
}
}
FactalMapData Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FractalMapData : MonoBehaviour {
public int gridWidth =20;
public int gridWHight =20;
public GridData fractalGrid ;
void Update () {
//TEST
fractalGrid =new GridData(gridWidth,gridWHight);
Debug.Log ("row" + fractalGrid.rows.Length); //Object reference not set to an instance of an object
Debug.Log ("colum" + fractalGrid.rows[0].colum.Length);//Object reference not set to an instance of an object
}
}
As suggested in my comment, I advise you to actually learn oop before constructing oop code.
But learning by mistakes isn't all that bad, so here the ones you made:
[System.Serializable] // not a mistake, but do you really need this?
public class GridData {
[System.Serializable]
public struct rowData{
public float[] colum;
}
// why are you using a struct with only one field in it
// do you really need a struct?
// PITFALL: you'll be wondering later on, why the values for numRows and numColums are the same for all instances
// Why? Because they are static! That means there are *not* instantiated
public static int numRows =30;
public static int numColums =20;
// You are initializing your rowData here
// and again in the constructor. What do you actually want?
public rowData[] rows = new rowData[numRows];
//
//Constructor
public GridData(int x, int y){
// As mentioned before:
// you are assigning instantiating values to static fields
numRows =y;
numColums = x;
// you are *defining* a local variable called rows and initializing it with an array of length numColums
// After we leave the constructor this get's lost
rowData[] rows = new rowData[numColums];
}
}
Another thing you should think about: Why are you creating a class
If you find, that you have a good reason, ask yourself what the responsibility of the class is. E.g.: Should it just hold some data, Does it provide any abstraction, Will it manipulate the data it has, should the data be exposed?
I think you have not answered most of these questions.
Here is how it could work
"I need a class that holds some grid data"
"I want the underlying data structure to be a one dimensional array" (for whatever reason)
"The abstraction is, that the class exposes the data as a two dimensional grid"
"I don't need to initialize the class with existing data" (for now)
Then you can implement the class
public class GridData {
// The concrete data doesn't have to be exposed
// let's make it private
private float[] data;
// let's use properties for this (= less code)
// get; means it's accessible as defined at the beginning (public)
// private set; means only the class it self can change these numbers
public int RowCount { get; private set; }
public int ColCount { get; private set; }
// I want to represent the data as a 2D grid so let's make a function
public float GetCell(int x, int y) {
// validate requests!
if(
x >= ColCount || x < 0
||
y >= RowCount || y < 0
) {
// don't be shy to throw exceptions!
// they communicate exceptional circumstances!
throw new ArgumentOutOfRangeException("Requested cell is not on grid");
}
return data[y * RowCount + x];
}
// I want the data to be set from outside
public float SetCell(int x, int y, float value) {
// excercise for you!
}
public GridData(int cols, int rows) {
RowCount = rows;
ColCount = cols;
this.data = new float[rows * cols];
}
}
Note that there are multiple ways to implement a class that conforms to the needs I formulated.
You never initialize public float[] colum; anywhere in your code.
As a result, when you invoke your constructor, although you correctly create an initialized rows array, the colum field of each rowData instance has not been initialized and will throw a null reference exception when trying to access the length of the collection.
public GridData(int x, int y){
numRows =y;
numColums = x;
rowData[] rows = new rowData[numColums]; // BUG HERE
}
Here you are declaring a LOCAL variable rows, with the same name as the instance field named rows. Thus the instance field rows is never assigned.
You mean:
public GridData(int x, int y){
numRows =y;
numColums = x;
rows = new rowData[numColums];
}

Accessing and setting the instance variable of one class from another class

I currently have a class called:
public class HeatmapComponent : GH_Component
I also have another class called:
public class HeatMap
Inside the Heatmap class I have two instance variables declared as:
public int _width;
public int _height;
I would like to be able to access and set the _width and _height variables from the HeatmapComponent class. I know this is a scope issue, but, I am a bit confused as to what needs to be done.
In my HeatmapComponent class, this was what I had in mind:
this._width = width; // width is declared somewhere in this class
this._height = height; // height is same as above
I apologize beforehand if this is a stupid question. Please let me know if I am missing code snippets. I'll be happy to provide.
You want to set the values of those two fields? They are readonly. You can do that only in the constructor.
public class HeatMap
{
private readonly int _width;
private readonly int _height;
public HeatMap(int wid, int hei)
{
_width = wid;
_height = hei;
}
}
And, as it is with passing things through constructor's params, you can use/provide them only when building a new instance. That's why they are called constructor and readonly fields:
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
void createMapAndDoSomething()
{
var hmap = new HeatMap(widthOfMap, heightOfMap);
hmap.thing();
}
}
If you don't want to create a new HeatMap, and if you want to be able to set the width/height from some 'external' place at any point in time, then:
they cannot be readonly
some public way of changing them must exist
For example:
public class HeatMap
{
private int _width;
private int _height;
public void SetSize(int wid, int hei)
{
_width = wid;
_height = hei;
}
}
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
private HeatMap oldMap;
void changeTheSizes()
{
oldMap.SetSize(widthOfMap, heightOfMap);
}
}
Or sometimes even better, use properties:
public class HeatMap
{
private int _width;
private int _height;
public int Width { set { _width = value; } }
public int Height { set { _height = value; } }
}
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
private HeatMap oldMap;
void changeTheSizes()
{
oldMap.Width = widthOfMap;
oldMap.Height = heightOfMap;
}
}
Before I answer your question, you have one major, major issue: readonly. That means that the value of the variable cannot be changed once the object is created. By anyone. Period.
Now, you have a couple ways to do this. The first is to use properties like Snorre said. In effect, you'd get this:
public class HeatMap
{
public int Width { get; set; }
public int Height { get; set; }
}
public class HeatMapComponent
{
private HeatMap myHeatMap; // Must have a reference to the object you want to change!
public void SomeMethod()
{
myHeatMap.Width = 10;
}
}
Now, the obvious downside here is that ANYONE can change the properties of HeatMap. If for some reason you really, really want to make HeatMap's width and height editable only by the HeatMapComponent, you can make HeatMapComponent an inner class, like this:
public class HeatMap
{
private int width;
private int height;
public class HeatMapComponent
{
public HeatMap myHeatMap;
public void SomeMethod()
{
myHeatMap.width = 10;
}
}
}
however, I would strongly advise you to rethink what you're trying to do. Public inner classes are actually quite rare, in my experience, as they can violate OOP principles easily. A different application design may suit you better.
Couple of things:
readonly keyword makes anything settable only in the constructor. Example:
class XYZ
{
private readonly int x;
public XYZ()
{
x = 10; //works
}
public void SomeMethod()
{
x = 100; //does not work since it is readonly
}
}
Then there's the various access modifiers: private is only accessible in the class itself, protected is accessible in inherited classes and public is accessible anywhere. Internal is accessible within the same assembly.
public class HeatMapComponent
{
HeatMap _map;
public HeatMapComponent()
{
_map = new HeatMap();
}
public void SomeMethod()
{
_map.Width = 10; //should work if Width is public and not readonly and if _map was initialized already, ie not null
}
}
This sounds like a homework question, and the problem is you are not understanding the lesson.
Here's a way to create your HeatMap class. It contains an overload so you can either set the Width and Height in the constructor or via a Set method:
public class HeatMap {
public HeatMap() {
Width = 0;
Height = 0;
}
public HeatMap(int width, int height) {
Width = width;
Height = height;
}
public void Set(int width, int height) {
Width = width;
Height = height;
}
public int Width { get; private set; }
public int Height { get; private set; }
}
To use this in your HeatmapComponent class, you only need to create an instance of your HeatMap. Here are two ways of doing that:
public HeatmapComponent() {
}
public void Test1(int width, int height) {
var hm = new HeatMap(width, height);
Console.WriteLine("Width: {0}, Height: {1}", hm.Width, hm.Height);
}
public static void Test2(int width, int height) {
var hm = new HeatMap();
hm.Set(width, height);
Console.WriteLine("Width: {0}, Height: {1}", hm.Width, hm.Height);
}
Be sure you understand what is going on, though.

Categories

Resources