Property or indexer cannot be assigned to - it is read only - c#

Hey i just started by C# class 2 weeks ago so i am beginner programmer
and i am having trouble with my code. i have 2 classes, one of them is the test case that runs the program and the other has private variables. my variables color, NumOfWheels, StartingPoint, CurrentSpeed, and Mileage says property or indexer cannot be assigned to - it is read only when i try to build it. how do i fix this?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Homework1
{
class Car
{
private string color;
private int numOfWheels;
private int startingPoint;
private int mileage;
private int currentSpeed;
public Car()
{
Color = "";
NumOfWheels = 4;
StartingPoint = 100000;
CurrentSpeed = 0;
Mileage = 0;
}
public Car(string color, int numOfWheels, int startingPoint, int currentSpeed, int mileage)
{
Color = color;
NumOfWheels = numOfWheels;
StartingPoint = startingPoint;
CurrentSpeed = currentSpeed;
Mileage = mileage;
}
public virtual void setcolor(string color)
{
this.color = color;
}
public virtual void setnumOfWheels(int numOfWheels)
{
this.numOfWheels = numOfWheels;
}
public virtual string Color
{
get
{
return color;
}
}
public virtual double NumOfWheels
{
get
{
return numOfWheels;
}
}
public virtual int StartingPoint
{
get
{
return startingPoint;
}
}
public virtual int CurrentSpeed
{
get
{
return currentSpeed;
}
}
public virtual int Mileage
{
get
{
return mileage;
}
}
public override string ToString()
{
return (" color " + color + " numOfWheels" + numOfWheels + "startingPoint " + startingPoint + "mileage" + mileage + "current speed" + currentSpeed);
}
}
}
********************************************************************************
/// this is the test case that runs the program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication8
{
class CarTest
{
static void Main(string[] args)
{
Car myCar = new Car();
Console.WriteLine("*****************************");
Console.WriteLine("* *");
Console.WriteLine("* WELCOME TO CAR MANAGER *");
Console.WriteLine("* By <<my Name>> *");
Console.WriteLine("* *");
Console.WriteLine("*****************************");
Console.WriteLine("\nEnter the number of wheels of a car");
int numOfWheels = Console.Read();
myCar.setWheels(numOfWheels);
Console.WriteLine("Enter the color of the car");
String color = Console.ReadLine();
Console.WriteLine("Current mileage will be set to zero");
Console.WriteLine("The current starting point will be set to 100000");
Console.Write("The current status of your car \n{0:D} Wheels, \n{1}, \n{2:D} Miles and \nCAR POINT = {3:D}", myCar.getNumOfWheels,
myCar.getColor, myCar.getMileage, myCar.getStartingPoint);
Console.WriteLine("\nEnter the owner's name");
String name = Console.ReadLine();
Console.WriteLine("Enter the miles the car ran in this week");
int milesThisWeek = Console.ReadLine;
myCar.setMileage(Mileage);
Console.WriteLine("This car is owned by n{1}", name);
Console.WriteLine("===>The current status of your car:");
Console.WriteLine("Wheels: " + myCar.getWheels());
Console.WriteLine("Color: " + myCar.getColor());
Console.WriteLine("Current Mileage: " + myCar.getMileage());
Console.WriteLine("Starting Point: " + myCar.getStartingPoint());
Console.WriteLine("************ Thank you for using CAR MANAGER *************");
Console.WriteLine("----------------------------------------------------------");
Console.WriteLine("----------------------------------------------------------");
Console.WriteLine("Press ENTER to close console…….");
}
}
}

You're trying to set a property:
Color = "";
(among other places) But that property doesn't have a setter, only a getter:
public virtual string Color
{
get
{
return color;
}
}
In order to set the value of a property, it needs a setter:
public virtual string Color
{
get
{
return color;
}
set
{
color = value;
}
}
(repeat for your other properties as well)
It looks like you're trying to create Java-like setter methods:
public virtual void setcolor(string color)
{
this.color = color;
}
This works, and you can call those instead of trying to set the properties:
setColor("");
But it's not the expected convention in C#. The properties can manage the backing variables themselves. In fact, you can remove the backing variables entirely and use auto-implemented properties for simple values:
public virtual string Color { get; set; }
If you just need to hold a value, a simple property does that just fine. Methods are more for operations in code, not for getting/setting simple values. (Additionally, you wouldn't want to get into the habit of calling a lot of methods from a constructor. A constructor should really just build the state of the object and nothing else.)

Related

C# Compound Interest Calculator Using a Loop (Error CS0103)

I want to create a Compound Interest Calculator in C# using two classes in different namespaces but can't for the life of me figure out why I keep getting errors.
PSA I am a beginner, I know this code probably looks awful, but please be kind.
Here is CompoundTest.cs
namespace CompoundTest
{
class Program
{
static void Main(string[] args)
{
CompoundClass newprogram = new CompoundClass();
Console.Write("\nPlease enter the initial balance for your account: ");
double balance = Convert.ToDouble(Console.ReadLine());
Console.Write("\nPlease enter the annual interest rate: ");
double interestRate = Convert.ToDouble(Console.ReadLine()) / 100;
Console.Write("\nHow many years will you acrue interest? ");
double annualAmount = Convert.ToDouble(Console.ReadLine());
Console.WriteLine($"Your balance after {annualAmount} years is {accountBalance:C}");
Console.ReadLine();
}
}
}
And here is Compound.cs
using System;
namespace Compound
{
public class CompoundClass
{
private double balance;
public int value { get; private set; }
public CompoundClass()
{
Balance = value;
}
public double Balance
{
get
{
return balance;
}
private set
{
if (value > 0)
{
balance = value;
}
}
}
public void Rate(double interestRate)
{
interestRate = value / 100;
}
public void Years(double annualAmount)
{
annualAmount = value * 12;
}
public void addMethod(double accountBalance)
{
for (int i = 1; i < annualAmount + 1; i++)
{
accountBalance = balance * Math.Pow(1 + interestRate / annualAmount, annualAmount * i);
}
}
}
}
I get the error:
CS0103 C# The name '..' does not exist in the current context - in the public void addMethod(double accountBalance) method
You are not storing any data on the CompoundClass, the method
public void Rate(double interestRate)
{
interestRate = value / 100;
}
only operates on the input parameter interestrate inside the functions scope, after that the result of the calculation is lost
If you want to reuse a variable on the entire lifetime of the CompoundClass, then define it as a member variable like:
private double _interestRate
and change your function to
public void Rate()
{
_interestRate = value / 100;
}
and for the annualAmount as well
private double _annualAmount;
public void Years()
{
_annualAmount = value * 12;
}
and your calculation to
public double addMethod(double accountBalance)
{
for (int i = 1; i < annualAmount + 1; i++)
{
accountBalance = balance * Math.Pow(1 + _interestRate / _annualAmount, _annualAmount * i);
}
return accountBalance;
}
There is more then one thing wrong with this code. And I am honestly not sure if I even got anything close to your problem yet.
using System;
namespace Compound
{
public class CompoundClass
{
private double balance;
public int value { get; private set; }
public CompoundClass()
{
//Balance with a big B is nowhere in context
Balance = value;
}
public double Balance
{
get
{
return balance;
}
private set
{
if (value > 0)
{
balance = value;
}
}
}
//As remarked by somebody else, this function does nothing. Without return or out parameter, interest rate will stay at nothing.
public void Rate(double interestRate)
{
interestRate = value / 100;
}
//The naming of this variable is bad. Did you mean "Amoung of Months"?
//Also as someone else pointed out, you do not return or otherwise persist this value
public void Years(double annualAmount)
{
annualAmount = value * 12;
}
//Method does not return anything.
//accountBalance is a local value and will not persist
public void addMethod(double accountBalance)
{
for (int i = 1; i < annualAmount + 1; i++)
{
//Avoid putting that much stuff into 1 line. It really messes with your ability to debug
//1-2 operations + 1 assignment to a temporary variable per line
//Anything more and you will have serious issues debugging this
accountBalance = balance * Math.Pow(1 + interestRate / annualAmount, annualAmount * i);
}
}
}
}
Generally the variables this works with should be either purely parameters (wich means it should be a static class with static functions) or mostly class variables. You have both things mixed all over the place.

How to return a string using methods

I am writing a class called Television that does a few simple controls, but I am running into an issue with my ToString method. "'Television.ToString()': not all code paths return a value". How would I go about returning either message? Any help is appreciated greatly, thank you.
class Television
{
private string manufacturer;
private int screenSize;
private bool powerOn = false; // the power is off by default
private int channel = 2; // channel is default set to 2
private int volume = 20; // volume default set to 20
public Television (string manu, int size) // The purpose of this constructor is to initialize the manufacturer and screen size fields.
{
manufacturer = manu;
screenSize = size;
}
public int GetVolume() // accessor method that returns volume
{
return volume;
}
public int GetChannel() // accessor method that returns channel
{
return channel;
}
public string GetManufacturer() // accessor method that returns manufacturer
{
return manufacturer;
}
public int GetScreenSize() // accessor method that returns screen sizes
{
return screenSize;
}
public void SetChannel(int userChannel) // mutator method that changes the channel
{
Console.WriteLine("What channel would you like to watch?: ");
userChannel = int.Parse(Console.ReadLine());
userChannel = channel;
}
public void power() // mutator method that turns the power on/off
{
powerOn = !powerOn;
}
public void IncreaseVolume() // mutator method that increases volume by 1
{
volume = volume + 1;
}
public void DecreaseVolume() // mutator method that decreases volume by 1
{
volume = volume - 1;
}
**public string ToString()
{
if (powerOn == false) {
Console.WriteLine("A " + screenSize + " inch " + manufacturer + " has been turned off.");
}
else if (powerOn == true)
{
Console.WriteLine("A " + screenSize + " inch " + manufacturer + " has been turned on.");
}**
}
}
}
ToString should override the base method to respect the polymorphism design and it must return a string but you return nothing:
public override string ToString()
{
string str = "A " + screenSize + " inch " + manufacturer + " has been turned ";
return str + ( powerOn ? "on." : "off." );
}
Or:
public override string ToString()
{
return $"A {screenSize} inch {manufacturer} is turned {(powerOn ? "on" : "off")}.";
}
Therefore you can use:
var television = new Television();
Console.WriteLine(television.ToString());
MessageBox.Show(television.ToString());
label.Text = television.ToString();

Assigning objects to an array C#

Struggling to assign objects to an array in C#.
The output of the code is unexpected because I get the nameOfProject.ClassName(?) x3 rather than name and life points of 3 monsters i added using my for loop.
Debug suggests monsters aren't being assigned. Is there a logical flaw that people like me should be looking out for?
class Monsters
{
public Monsters(string name, int points)
{
var monsterName = name;
var monsterLifePoints = points;
}
}
class Program
{
static void Main(string[] args)
{
Monsters[] monster = new Monsters[3];
for (int i = 0; i < monster.Length; i++)
{
Console.WriteLine("Please enter a name");
string name = Console.ReadLine();
Console.WriteLine("Please enter life points");
int points = Convert.ToInt32(Console.ReadLine());
monster[i] = new Monsters(name,points);
Console.Clear();
}
foreach (var element in monster)
{
Console.WriteLine(element);
}
Console.ReadKey();
}
Assignment works just fine. The problem is that you never asign the monster's name and points to a field or property:
class Monsters
{
public Monsters(string name, int points)
{
var monsterName = name;
var monsterLifePoints = points;
}
}
This code just assigns the input to local values and then discards them.
Your class should look like this:
class Monsters
{
public string Name {get;set;}
public int Points {get;set;}
public Monsters(string name, int points)
{
Name = name;
Points = points;
}
}
This line still won't print the details :
Console.WriteLine(element);
You need to either create a string from the properties :
Console.WriteLine($"{element.Name} {element.Points}");
Or override the ToString() method of your class :
public override string ToString()
{
return $"{element.Name} {element.Points}";
}
How should WriteLine know that you want to print those two properties and not e.g. the type-name (which it does per default) or any other wierd string? You have to tell your program how to do this. This is done by overriding ToString
class Monster
{
public override string ToString() {
return this.name + " " + this.lifePoints;
}
}
Furthermore your variables need to be fields:
class Monster
{
private readonly string name;
private readonly int lifePoints;
Monster(string name, int points)
{
this.name = name;
this.lifePoints = points;
}
}

Private accessible vs Public

I have problems with the encapsulation, and I don't where the problem is. Why can the line be altered after it has been created? This tells me something is wrong in my "line-class" and needs to be encapsulated. Advise would be much appreciated.
When calling "pa.X = 4" and "startpos.Y = 7" this should not change the line for me, but it does. I expect that all the lines are unchanged when the program has finished.
Dotclass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dot
{
class Dot
{
private int x;
private int y;
public Dot()
{
this.X = 0;
this.Y = 0;
}
public Dot(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X
{
get
{ return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
}
}
Lineclass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dot
{
class Line
{
private Dot startdot;
private Dot enddot;
private double length;
public Line(Dot pa, Dot pb)
{
this.startdot = pa;
this.enddot = pb;
}
public double Size()
{
double a = (double)(enddot.X - startdot.X);
double b = (double)(enddot.Y - startdot.Y);
return length = Math.Sqrt(a * a + b * b);
}
public Dot Position()
{
return startdot;
}
}
}
Main:
using System;
namespace Dot
{
class Program
{
public static void Main()
{
Dot pa = new Dot();
Dot pb = new Dot(-10, -10);
Console.WriteLine("Dot pa, position = (" + pa.X + ", " + pa.Y + ")");
Console.WriteLine("Dot pb, position = (" + pb.X + ", " + pb.Y + ")");
Line line = new Line(pa, pb);
Print("Run 1 off line", line);
pa.X = 4;
Print("Run 2 off line", line);
Dot startpos = line.Position();
startpos.Y = 7;
Print("Run 3 off line", line);
}
private static void print(string text, Line line)
{
double length = line.Size();
Dot startPos = line.Position();
Console.WriteLine("\n" + text);
Console.WriteLine("Längd = {0 :f4} length", length);
Console.WriteLine("Position = ({0},{1})", startPos.X, startPos.Y);
Console.ReadLine();
}
}
}
Why can the line be altered after it has been created?
The reason is that class Dot is a reference type, and you want a value type, struct:
// please, notice "struct"
public struct Dot {
// you don't need separate fields, but properties
public int X {get; set;}
public int Y {get; set;}
public Dot(int x, int y) {
X = x;
Y = y;
}
}
....
EDIT: I suggest turning public Dot Position() into property as well:
class Line {
...
public Dot Position {
get {
return startdot;
}
set {
startdot = value;
}
}
}
and so you can "control the angles":
line.Position = new Dot(line.Position.X, 5);

Using multiple classes

I am trying to make a simple program that asks the user to enter an integer. Once the program receives the input it takes and stores it and then counts from 1 to the input integer and sums the total of the count. Then it displays the results in a meaningful way to the user and prompts them if they would like to process another number. The point of this program is to use loops and multiple classes. I know that I am really close to the desired end product but cannot figure out why the AccumulateValue() method is not working properly. It does not seem to be going into the conditional while statement that I made. If anyone could give me some insight to my problem that would be great!
Here is my code:
AccumulatorApp.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project
{
class AccumulatorApp
{
static void Main(string[] args)
{
string loopControl = "Y";
int sum;
int enteredValue;
DisplayTitle();
while (loopControl == "Y" || loopControl == "YES")
{
enteredValue = InputInteger(0);
Accumulator number = new Accumulator(enteredValue);
sum = number.AccumulateValues();
DisplayOutput(sum, enteredValue);
Console.Write("\tWould you like to process another number? \n\t\t<Y or N>: ");
loopControl = Console.ReadLine().ToUpper();
}
}
public static void DisplayTitle()
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
Console.Clear();
Console.WriteLine();
Console.WriteLine("\tProgramming Assignment 05 - Accumulator - Robert");
DrawLine();
}
public static int InputInteger(int enteredValue)
{
Console.Write("\tPlease enter a positive integer: ");
enteredValue = Convert.ToInt32(Console.ReadLine());
if (enteredValue > 0)
{
return enteredValue;
}
else
{
Console.WriteLine("\tInvalid input. Please enter a POSITIVE integer: ");
enteredValue = Convert.ToInt32(Console.ReadLine());
}
return enteredValue;
/*
Console.Write("Please enter a positive integer: ");
int enteredValue = Convert.ToInt32(Console.ReadLine());
return enteredValue;
* */
}
public static void DisplayOutput(int sum, int inputValue)
{
Console.WriteLine("\tThe inputed integer is: {0}", inputValue);
Console.WriteLine("\tThe sum of 1 through {0} = {1}", inputValue, sum);
DrawLine();
}
public static void DrawLine()
{
Console.WriteLine("\t______________________________________________________");
Console.WriteLine();
}
}
}
Accumulator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project
{
class Accumulator
{
int integerEntered;
public Accumulator()
{
}
public Accumulator(int integerEntered)
{
int enteredInteger = integerEntered;
}
public int AccumulateValues()
{
int accumulatedValue = 0;
int counterValue = 1;
while (counterValue <= integerEntered)
{
Console.WriteLine("\tPasses through loop = {0}", accumulatedValue);
accumulatedValue = accumulatedValue + counterValue;
counterValue = counterValue + 1;
}
return accumulatedValue;
}
}
}
When you are instantiating a new instance of Accumulator through it's constructor containing one int argument you were setting the passed value equal to the field within the class (Setting them both to 0.)
Your accumulator class should look like this:
class Accumulator
{
int integerEntered;
public Accumulator()
{
}
public Accumulator(int passedInteger)
{
//Local field is equal to passedInteger, not the other way around.
integerEntered = passedInteger;
}
public int AccumulateValues()
{
int accumulatedValue = 0;
int counterValue = 1;
while (counterValue <= integerEntered)
{
Console.WriteLine("\tPasses through loop = {0}", accumulatedValue);
accumulatedValue = accumulatedValue + counterValue;
//Increment does the same thing you were doing
counterValue++;
}
return accumulatedValue;
}
}
It looks like the problem may actually be with your value constructor. When this line is called:
Accumulator number = new Accumulator(enteredValue);
A new Accumulator is being made with your value constructor:
public Accumulator(int integerEntered)
{
int enteredInteger = integerEntered;
}
The problem is that integerEntered isn't really saved anywhere and once enteredInteger goes out of scope (end of constructor), the value that was entered is essentially lost as far as the Accumulator object is concerned. I think what you want is:
public Accumulator(int integerEntered)
{
integerEntered = integerEntered;
}
As a heads up, you may have to do this.integerEntered = integerEntered;
Also I think you want to subtract 1 from integerEntered each iteration of your while loop in AccumulateValues().
There 2 -3 things needs to be changed
1) you are not assigning values to integerEntered in your constructor so I have changed it
2) you should integerEntered as a property so i have changed it to public int integerEntered { get; set; }
3) the logic of calculating to count AccumulateValues .. actually mathematical formula is the sum up to integer n is = (n * (n+1))/2 so i have changed it too
try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project
{
class Accumulator
{
public int integerEntered { get; set; }
public Accumulator()
{
}
public Accumulator(int integerPassed)
{
integerEntered = integerPassed;
}
public int AccumulateValues()
{
int accumulatedValue = 0;
if(integerEntered > 0)
{
accumulatedValue = (integerEntered * (integerEntered + 1))/2;
}
return accumulatedValue;
}
}
}

Categories

Resources