A simple program using properties to encapsulate.. Farmer has field snumberofCows andfeedMultiplier,
and write to console BagsOfFeed= numberofCows* feedMultiplier
namespace numberOfCows
{
class Farmer
{
private int bagsOfFeed;
//public const int FeedMultiplier = 30;
private int numberOfCows;
private int feedMultiplier;
//private int bagsOfFeed;
public Farmer(int numberOfCows, int feedMultiplie)
{
feedMultiplier = feedMultiplie;
//this.feedMultiplier = feedMultiplie;
NumberOfCows = numberOfCows;
//this.numberOfCows = numberOfCows;
}
public int FeedMultiplier { get { return feedMultiplier; } }
public int NumberOfCows
{
get
{
return numberOfCows;
}
set
{
numberOfCows = value;
//BagsOfFeed = numberOfCows * FeedMultiplier;
}
}
//READ ONLY PROPERTY
public int BagsOfFeed {
get { return bagsOfFeed; }
set { bagsOfFeed = NumberOfCows * FeedMultiplier; }
}
}
}
When call farmer = new Farmer( 15,30 ); Console.WriteLine("I need {0} bags of feed for {1} cows",farmer.BagsOfFeed, farmer.NumberOfCows); returns 0 BagsOfFeed...So I don't know where i goes wrong..[I thought properties is used to retrieve values which is to read sth out...also,,when should i use private set..]
The set method for BagsOfFeed is never called since you never do BagsOfFeed = something;, so the calculation is never done. You should probably have the calculation in the get method, and remove the field for it. Your class also has other fields that don't need to exist. For example, with the FeedMultiplier property, you can use private set; (this is called an auto-property) instead of having just a get with a backing field. It could be rewritten as:
class Farmer
{
public Farmer(int numberOfCows, int feedMultiplier)
{
this.FeedMultiplier = feedMultiplier;
this.NumberOfCows = numberOfCows;
}
public int FeedMultiplier { get; private set; }
public int NumberOfCows { get; set; }
public int BagsOfFeed {
get { return NumberOfCows * FeedMultiplier; }
}
}
This shows the correct result in your example:
I need 450 bags of feed for 15 cows
BagsOfFeed setter is never called (and shouldn't be, as it's calculated based of values of other properties). This property should look like that:
//READ ONLY PROPERTY
public int BagsOfFeed {
get { return NumberOfCows * FeedMultiplier; }
}
With that, private int bagsOfFeed; can be removed as it's unnecessary.
Related
here is my main method:
string input = Console.ReadLine(); // 2006 2000 false 1000 500 Windows
List<string> inputs = input.Split(" ").ToList();
Computer one = new Computer(int.Parse(inputs[0]), int.Parse(inputs[1]), bool.Parse(inputs[2]), double.Parse(inputs[3]), double.Parse(inputs[4]), inputs[5]);
one.Print(); // 2006, 2000, false, 1000, 500, Windows
input = Console.ReadLine(); //changeOperatingSystem
if (input == "changeOperatingSystem")
{
string newOperationSystem = Console.ReadLine(); //Linux
Computer two = new Computer(newOperationSystem);
}
one.Print(); //2006, 2000, false, 1000, 500, Linux
the "//" marks what the input and the output look like.
This is my Computer.cs:
private int years;
private int price;
private bool isNotebook;
private double hardDiskMemory;
private double freeMemory;
private string operationSystem;
private string newOperationSystem;
public Computer(int years, int price, bool isNotebook, double hardDiskMemory, double freeMemory, string operationSystem)
{
Years = years;
Price = price;
IsNotebook = isNotebook;
HardDiskMemory = hardDiskMemory;
FreeMemory = freeMemory;
OperationSystem = operationSystem;
}
public Computer(string newOperationSystem)
{
OperationSystem = newOperationSystem;
}
public int Years
{
get { return years; }
set
{
years = value;
}
}
public int Price
{
get { return price; }
set
{
price = value;
}
}
public bool IsNotebook
{
get { return isNotebook; }
set
{
isNotebook = value;
}
}
public double HardDiskMemory
{
get { return hardDiskMemory; }
set
{
hardDiskMemory = value;
}
}
public double FreeMemory
{
get { return freeMemory; }
set
{
freeMemory = value;
}
}
public string OperationSystem
{
get { return operationSystem; }
set
{
operationSystem = value;
}
}
public string NewOperationSystem
{
get { return NewOperationSystem; }
set
{
newOperationSystem = value;
}
}
public void Print()
{
Console.WriteLine($"{years}, {price}, {isNotebook}, {hardDiskMemory}, {FreeMemory}, {operationSystem}");
}
what I want this program to do is whenever the input submitted by the user is "changeOperationSystem" the program gives the user another input where they submit the new Operation system for the pc. Then with the constructor, the Computer.Cs receives the string newOperationSystem, which then should replace the value operationSystem as I tried to do in the constructor: OperationSystem = newOperationSystem, but it doesn't work. I am stil learning classes so don't go hard on me.
It seems to me you are trying to change one property of a class. All you have to do is use the property set method
one.OperationSystem = newOperationSystem;
and remove the property NewOperationSystem altogether.
Here is a bare bones skeleton code of instantiating a class with a constructor and then changing one of the properties
public class Foo
{
private int _a;
private string _b;
private readonly float _c;
public Foo(int a, string b, float c)
{
_a = a;
_b = b;
_c = c;
}
public int A { get => _a; set => _a = value; }
public string B { get => _b; set => _b = value; }
public float C => _c;
public override string ToString()
{
return $"{_a}, {_b}, {_c}";
}
}
class Program
{
static void Main(string[] args)
{
Foo one = new Foo(100, "Philip", 0.75f);
Console.WriteLine(one);
//100, Philip, 0.75
one.B = "Spencer";
Console.WriteLine(one);
//100, Spencer, 0.75
}
}
Another feature of the code above is that there is no need to create a .Print() method, if you can take advantage of the built-in .ToString() which gets called automatically during a Console.WriteLine() or any other operations that require a string input from my class.
Finally, I added a read-only property C to demonstrate that this design is possible. You will not be able to write one.C = 0.25f; since the property is read-only.
This question already has answers here:
Unsure about parameters when calling base constructor from derived class
(2 answers)
Closed 2 years ago.
I'm creating a .NET core menu-based console app that allows you to add and manage players from different sports.
My Player class:
abstract class Player
{
enum PlayerType
{
HockeyPlayer,
BacketballPlayer,
BaseballPlayer
}
public abstract void Points();
private long playerId;
private string playerName;
private string teamName;
private int gamesPlayed;
public long PlayerId
{
get { return playerId; }
set { playerId = value; }
}
public string PlayerName
{
get { return playerName; }
set { playerName = value; }
}
public string TeamName
{
get { return teamName; }
set { teamName = value; }
}
public int GamesPlayed
{
get { return gamesPlayed; }
set { gamesPlayed = value; }
}
}
class HockeyPlayer : Player
{
private int assists;
private int goals;
public override void Points()
{
int totalPoints = assists + (2 * goals);
}
public int Assists
{
get { return assists; }
set { assists = value; }
}
public int Goals
{
get { return goals; }
set { goals = value; }
}
}
class BasketballPlayer : Player
{
private int fieldGoals;
private int threePointers;
public override void Points()
{
int totalPoints = (fieldGoals - threePointers) + (2 * threePointers);
}
public int FieldGoals
{
get { return fieldGoals; }
set { fieldGoals = value; }
}
public int ThreePointer
{
get { return threePointers; }
set { threePointers = value; }
}
}
class BaseballPlayer : Player
{
private int runs;
private int homeRuns;
public override void Points()
{
int totalPoints = (runs - homeRuns) + (2 * homeRuns);
}
public int Runs
{
get { return runs; }
set { runs = value; }
}
}
And a snippet of my main class:
class Controller
{
static void Main(string[] args)
{
List<Player> players = new List<Player>()
{
new HockeyPlayer(1, "Mitch Marner", "Toronto Maple Leafs", 5)
};
In the controller I am trying to populate the list with some sample data, but obviously I don't have a constructor in my derived HockeyPlayer class. How do I create a constructor for HockeyPlayer where the arguments are 'playerId', 'playerName', 'teamName', and 'gamesPlayed' which come from the parent class. I feel like I'm missing something very simple here.
A funny thing is that you are using 'object initialization' for the list, but trying to call the constructor of HockeyPlayer, where you also could use the object initialization method.
The object initialization is executed after the constructor (assigning properties) but enables construction and property initialization in one single statement
For example:
List<Player> players = new List<Player>()
{
new HockeyPlayer(1, "Mitch Marner", "Toronto Maple Leafs", 5);
};
List<Player> players = new List<Player>()
{
new HockeyPlayer
{
PlayerId = 1,
PlayerName = "Mitch Marner",
TeamName = "Toronto Maple Leafs",
GamesPlayed = 5
}
};
Constructors are usefull when certain parameters are mandatory. This way you force an initial value for a field/property.
Object initializers is just syntactic sugar for constructing and assigning properties. With a big difference (like i said) an object initializer can be treated as a single statement. (therefor you can pass it as an argument to a function.)
var player = new HockeyPlayer
{
PlayerId = 1,
PlayerName = "Mitch Marner",
TeamName = "Toronto Maple Leafs",
GamesPlayed = 5
}
VS
var player = new HockeyPlayer();
player.PlayerId = 1;
player.PlayerName = "Mitch Marner";
player.TeamName = "Toronto Maple Leafs";
player.GamesPlayed = 5;
I have this class:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get; set; }
}
and a list
List<Test> myTestList;
How can I make the value of the field DoubleNumber in myTestList equal to twice the value of Number? Note that I am okay to create another list if that's needed.
If I understand your question correctly:
foreach(Test item in myList) {
item.DoubleNumber = 2*item.Number;
}
Or, if it's ok, just remove the setter and modify the getter to return 2x Number:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get { return 2* this.Number; } } //completely remove setter
}
Or, if you still want to be able to modify DoubleNumber:
public class Test {
private int m_num;
private int m_doubleNum;
public string Id {
get;
set;
}
public int Number {
get {
return this.m_num;
}
set {
this.m_num = value;
this.m_doubleNum = 2 * value; //when Number is set, update m_doubleNum too
}
}
public int DoubleNumber {
get {
return this.m_doubleNum;
}
set {
this.m_doubleNum = value; //allow manual setting of DoubleNumber
//or maybe also modify Number here?
//this.m_num = value / 2;
}
}
}
One way it could be using a foreach statement:
foreach(var item in myTestList)
{
item.DoubleNumber = 2*item.Number;
}
Another way it could be to use LINQ.
var result = myTestList.Select(test => new Test
{
test.Id,
test.Number,
DoubleNumber = 2*test.Number;
})
.ToList();
Among the two ways I would prefer the first one, since it's more clear what you are trying to do and more performant (in the second approach you have to create a new object for each object in myTestList).
My program throws this exception:
System.StackOverflowException
when the compiler executes the set property.
The wine class:
class wine
{
public int year;
public string name;
public static int no = 5;
public wine(int x, string y)
{
year = x;
name = y;
no++;
}
public int price
{
get
{
return no * 5;
}
set
{
price = value;
}
}
}
The Program class:
class Program
{
static void Main(string[] args)
{
wine w1 = new wine(1820, "Jack Daniels");
Console.WriteLine("price is " + w1.price);
w1.price = 90;
Console.WriteLine(w1.price);
Console.ReadLine();
}
}
When setting the price property, you invoke the setter, which invokes the setter which invokes the setter, etc..
Solution:
public int _price;
public int price
{
get
{
return no * 5;
}
set
{
_price = value;
}
}
You're setting the value of the setter from within the setter. This is an infinite loop, hence the StackOverflowException.
You probably meant to use a backing field no as per your getter:
public int price
{
get
{
return no * 5;
}
set
{
no = value/5;
}
}
or perhaps use its own backing field.
private int _price;
public int price
{
get
{
return _price;
}
set
{
_price = value;;
}
}
However, if the latter is the case, you dont need the backing field at all, you can use an auto property:
public int price { get; set; } // same as above code!
(Side note: Properties should start with an uppercase - Price not price)
Your property setter calls itself when you set any value, thus it produces an stack overflow, I think what you wanted to do was:
public int price
{
get
{
return no * 5;
}
set
{
no = value / 5;
}
}
class Log
{
public int LocationId { set { value = 1; } get; }
}
Will this set the default value for Log as 1 when i use like this: Log
l=new log(); Console.Writeline(l.LocationId);
?
I am aware of the normal way of using a property but will this also work?
The proper way to do it is in the constructor:
class Log {
public Log() {
LocationId = 1;
}
public int LocationId { set; get; }
}
No, you should do like this:
class Log
{
private int locationID = 1; //This is a default value
public int LocationId
{
set
{
locationID = value;
}
get
{
return locationID;
}
}
}