I have a code that uses inheritance in C# and I seem to have lost my price variable along the way. How can I get my price variable to work with the child classes when the parent class doesn't have it as a parameter? Please note: this has been submitted and marked, I'm not looking for extra marks, just trying to improve my learning.
Not sure if this is enough code to help, but I didn't want to flood the screen. Basically the PerformBuyStock method is in the program file and it records the price variable along with the quantity. However once the transaction is executed through the transaction class, because it doesn't have 3 parameters (stock, price, quantity) like the StockPurchaseTransaction class, then the price reverts to 0 when it executes printSummary. How do I get the price variable to still be there without changing the Transaction class? Thank you for any help you may be able to provide.
public abstract class Transaction
{
protected readonly Stock _stock;
protected readonly decimal _price;
protected readonly int _quantity;
protected readonly string SummaryLine;
public Transaction(Stock stock, int quantity)
{
_quantity = quantity;
_stock = stock;
SummaryLine = ($" - {_stock.Name} x {_quantity} #${_price}");
}
}
public class StockPurchaseTransaction : Transaction
{
public StockPurchaseTransaction(Stock stock, decimal price, int quantity) :base(stock, quantity)
{
stock = _stock;
price = _price;
quantity = _quantity;
}
public override void PrintSummary()
{
Console.WriteLine($"BUY {SummaryLine}");
}
}
private static void PerformBuyStock(Warehouse toWarehouse)
{
Stock stock = FindStockItem(toWarehouse);
if (stock == null) return;
int quantity;
decimal price;
Console.WriteLine($"Quantity of {stock.Name} purchased:");
quantity = Convert.ToInt32(Console.ReadLine());
Console.WriteLine($"Price per item purchased: ");
price = Convert.ToDecimal(Console.ReadLine());
StockPurchaseTransaction purchase;
purchase = new StockPurchaseTransaction(stock, price, quantity);
toWarehouse.ExecuteTransaction(purchase);
purchase.PrintSummary();
}
public void ExecuteTransaction(Transaction transaction)
{
_transactions.Add(transaction);
transaction.Execute();
}
the price reverts to 0 when it executes printSummary. How do I get the price variable to still be there without changing the Transaction class?
The issue is that the base class constructor is what sets the SummaryLine field, which is used to print the summary later. But at the time that that field is set, the _price field hasn't been initialized to the caller-provided value (indeed, it never is). It still has the default value of 0.
It certainly doesn't help that in the subclass constructor, you aren't even assigning the field correctly. The variables are on the wrong side of each assignment operator. As it happens, if you'd put them on the correct side, you'd have gotten a helpful compile-time error message explaining that the subclass constructor isn't allowed to assign a value to the readonly fields in the base class.
Anyway…
To fix it without changing the Transaction class? Well, the only way to do that is to add code in your subclass StockPurchaseTransaction that mirrors the code in the base class, but fixes the bugs that exist in it.
That might look something like this:
public StockPurchaseTransaction(Stock stock, decimal price, int quantity) :base(stock, quantity)
{
// To be clear: these three assignments are incorrect, and accomplish nothing
stock = _stock;
price = _price;
quantity = _quantity;
// This assignment would "fix" the problem, but it's not really the right way,
// and the field is readonly so this won't actually compile
SummaryLine = ($" - {stock.Name} x {quantity} #${price}");
}
Except that won't work, because unlike the assignments before it, the correct assignment of SummaryLine won't work as long as the base class field is readonly.
But really, the base class constructor is what's wrong, and that's where the fix ought to go:
public Transaction(Stock stock, int quantity, decimal price)
{
_quantity = quantity;
_stock = stock;
_price = price;
SummaryLine = ($" - {_stock.Name} x {_quantity} #${_price}");
}
Of course, then you'd need to add the price parameter to the base class constructor call:
public StockPurchaseTransaction(Stock stock, decimal price, int quantity)
: base(stock, quantity, price) { }
Note that if you do it that way, then the subclass constructor has nothing to do. All of the real work is done in the base class.
Bottom line, it's impossible to do what you are literally asking. The base class has bugs in it, and because of the readonly fields, you can't correct for those bugs in the subclass. They have to be fixed in the base class.
Related
I am curious to know what is the proper way of writing a constructor or rather when do I write it this way or the other.
I would also like to know why would you change the name of the field in the construcor, like I did in the first constructor with the field address.
Thank you for your help.
For example lets say you have a class Shipment with four fields: String item, Double price, String address, Double weight.
class Shipment
{
private string item;
private double price;
private string address;
private double weight;
public Shipment(string item, double price, string addr, double weight)
{
this.item=item;
this.price=price;
address=addr;
this.weight=weight;
}
public Shipment()
{
item="Football jersey";
price=35.99;
address="8520 Washington Dr.Toledo, OH 43612"
weight=0.400;
}
}
I would change the default constructor definition like this,
public Shipment : this ("Football jersey", 35.99, "8520 Washington Dr.Toledo, OH 43612", 0.400 )
{
}
This reuses the parameterized constructor and makes your code a bit more concise.
The rest of your code is ok. The usage of this in the constructor is pretty standard and it prevents you from inventing other names for the constructor arguments (ex - addressParams).
I have an Account class that contain a readonly variable balance.
Constructor will assign default value as 0.
But i want to update that value when I call CashIn method.
I tried this:
class Account
{
private string name;
private readonly double balance;
public Account(string n, double b)
{
name = n;
balance = b;
}
public void CashIn(double amount)
{
balance = balance+amount;
}
}
But as I know, readonly variable could be assigned through constructor or field.
Is it possible to update balance when i call CashIn method?
If yes then Please describe me how?
There is a big difference between the readonly modifier and the concept of a "read only" property.
The readonly modifier means your field can only be set in the constructor. You will not be able to set that variable to anything else outside of the constructor. Given the context of your code (a bank account simulator) it seems weird that you would have a balance that never, ever changes. Which leads me to believe you want a read only property.
A property is the preferred way of storing simple data that has get/set methods. For a bank account simulator it would be really bad to just have the balance exposed with a public setter right? So I think in that context it makes more sense to have a property with a public read, and a private set:
public decimal Balance { get; private set; }
This allows it to be read publicly but its only allowed to be modified inside the class (i.e from a custom method you write like CashIn())
public void CashIn(decimal amount)
{
Balance += amount;
}
Please note how I use decimal instead of double. Monetary values should always be represented as decimal, this is why it exists
The entire point of readonly is that you cannot do this, except in the constructor. Since readonly is a language level feature, not a strict runtime guarantee: you can cheat (via reflection or unsafe or various other evils), but it seems to me that the most pragmatic thing is to: remove the readonly modifier. Since you don't seem to want it to be read-only.
A simple solution is to remove a read-only tag for a variable. you can not change a value of read-only variables once it's initialized.
you can initialize it while creating the object and thereafter it will be treated as a constant for the lifetime of that object.
Create a private variable, and a Public Readonly Property that return its value, so you can edit the variable from the same class, but it is read only to other classes.
private double balance_;
public double Balance
{
get
{
return balance_;
}
}
Or you can use private set
public double Balance { get; private set; }
Check this link for more info: understanding private setters
Thanks in advance guys. I am quite new to coding so please be patient. Below is a piece of code I am working on. This is the complete code below. It's as follows:
using System;
public class Product
{
private string name;
private decimal price;
public string Name
{
get
{ return name; }
set
{ name = value; }
}
public decimal Price
{
get
{ return price; }
set
{ price = value; }
}
public Product(string name, decimal price)
{
this.name = name;
this.price = price;
}
}
In the page load method, an object is instantiated and the constructor is called as follows:
private void Page_Load(object sender, EventArgs e)
{
Product saleProduct = new Product("Kitchen Garbage", 49.99M);
}
When the product is created, the constructor is initialised, with the above values. Now if you look in the constructor, you have:
this.name = name;
and
this.price = price;
After the above two lines of code are executed, the property accessors automatically assign the private variables ("name" and "price") with the intended values.
So how are the lines:
this.name = name;
and
this.price = price;
able to call the public accessors, named "Name" and "Price"?
I have only seen when a public accessor is explicitly called such as:
saleProduct.Name = "Kitchen Garbage";
I don't understand how:
this.name = name;
and
this.price = price;
can access a private variable directly. I thought the whole point of property accessors was that you had to go via the property name in order to access the private variables such as:
saleProduct.Name = "Kitchen Garbage";
Can you help and explain how
this.name = name;
and
this.price = price;
is able to access the public properties? Even the name of the properties ie "Name" and "Price" are changed to "Kitchen Garbage" and "49.99" respectively when the above two lines of code are executed.
Also, how does
this.name = name;
and
this.price = price;
know which public accessor to call?
I have searched everywhere for an explanation but no luck.
Thank you.
The private members name and price are accessible in all non-static methods within the class Product. Since the constructor for Product is part of the class, the members are accessible there as well.
Your constructor is not using the public properties Name and Price. They retrieve their values from the corresponding private members.
this.name refers to private string name;. It's private, so only code inside the class can refer to it.
The this. prefix is only required because otherwise the code would be ambiguous, since there's a parameter called name as well.
The public accessor public string Name does not have any storage of its own. It passes through to the private field name.
The code this.name = name; does not touch the property Name - it's the other way around.
When you do this.name = name;, you are setting the value of the private field called name.
Whenever you access the public property Name, you are indirectly accessing that same field (name).
Look at the definition of the property:
get { return name; }
Note that here, name refers to the same field as this.name. You could change it to this.name and there'd be no effect. It's just not required here, since there's no ambiguity.
this.name = name;
and
this.price = price;
are used in the Constructor for the Product class. Private members are accessible from the Constructor (as well as from any non-static method on the class).
Basically, when you 'new' an object, the memory structure of the object is allocated, and then the constructor is called to allow for any initialization of that object. Making the name and price member variables private just means that you can only access them from inside the class members themselves, of which the constructor is.
The public properties Name and Price, as implemented here, are just wrappers around those private name and price variables, and allow you to do other things when setting or fetching (imagine wanting to count the number of times a value is referenced: you could increment some counter in the get{} of a public property).
in your constructor you are not setting the values via the public setter, you're setting the private backing field directly.
FYI I believe it is generally considered best practice to name class level items with an Upper letter (or underscore sometimes in the case of members/backing fields?), and function level variables and parameters with a lower letter. (Don't quote me on this paragraph :P)
so to set the field via it's setter just do:
public class Foo
{
private string _bar;
public string Bar
{
set
{
this._bar = value;
}
get
{
return _bar;
}
}
public Foo(string bar)
{
this.Bar = bar;
}
}
vs.
public Foo(string bar)
{
this._bar = bar
}
The above is equivalent to what you're doing in your code. Note with your current implementation it doesn't really make a difference, since you have no additional logic in your setter. If you did however, in your implementation you would miss out on that additional logic.
note i changed the variables around a bit to make it more obvious what's being done.
to demonstrate that point consider this:
public class Foo
private string _bar;
public string Bar
{
set
{
this._bar = value + " blah blah";
}
get
{
return _bar;
}
}
public Foo()
{
this.Bar = "test";
Console.WriteLine(Bar); // outputs "test blah blah"
this._bar = "test";
Console.WriteLine(Bar); // outputs "test"
}
}
The lower cased name and price are private 'backing' variables for the public Name and Price variables. They can only be accessed from within the class itself. The reason for using this.price is because the method is taking a param called 'price' so you need to specify that you're setting the classes field and not assigning to the local variable. You'll often see this in constructors, personally I would choose to name the arguments something different than the fields in my class and then it wouldn't be necessary.
This is probably a simple thing to fix. I'm a university student and we just started polymorphism, so the concept is still puzzling to me.
abstract class IncreaseTransaction
{
private string _Description;
private decimal _Amount;
protected IncreaseTransaction(string description, decimal amount)
{
_Description = description;
_Amount = amount;
}
}
class Deposit : IncreaseTransaction
{
public Deposit(string description, decimal amount) : base("Deposit", amount)
{
}
}
static void Main(string[] args)
{
Customer fred = new Customer("Fred");
SavingsAccount fredSavings = new SavingsAccount();
fredSavings.AddTransaction(new Deposit(500.00M));
}
When a new deposit is instantiated, I want the literal string "Deposit" to be used as the description for the transaction. However, I'm getting an error stating 'SampleNamespace.Deposit does not contain a constructor that takes one argument'. So, the string is not being inherited, and I am unsure how to fix this. I would greatly appreciate any help!
Your constructor for Deposit takes two parameters:
public Deposit(string description, decimal amount) : base("Deposit", amount)
Since you're setting "Deposit" in the call to base(), you don't need 'string description' in that constructor. It should look like:
public Deposit(decimal amount) : base("Deposit", amount)
The following line should no longer throw an error:
fredSavings.AddTransaction(new Deposit(500.00M));
Additional Explanation: Constructors are not inherited like members or properties, but are unique to both the child and parent. The child (Deposit) has to invoke the base class's (IncreaseTransaction) constructor, but it does not need to require the same parameters in its own constructor.
Here is an old (but good) discussion of why this is the case: Why are constructors not inherited?
I want my object to be able to type in an double or a string such as getting an input for salary. I have my code working with a property that allows for a double only. I know that property overloading isn't supported from the other postings at this site. I also know that setters are going to allow me to get an string input for salary. I don't understand how to overload. I have some of the template code here:
private double salary = 20000;
public Employee()
{
}
public Employee(double sal)
{
salary = sal;
}
public double Salary
{
get { return salary; }
set { salary = value; }
}
public void SetSalary(string sal)
{
salary = Convert.ToString(sal);
}
Error code:
can not implicitly covert type string to double
I want to be able to have an object be able to overload salary using a setter in C#. I am a student and understand most of the basics. Thanks ahead of time for any help.
public void SetSalary(string sal)
{
salary = Convert.ToString(sal);
}
You are converting the parameter, which is already a string, to a string, and trying to assign it to a field that is of type double.
salary = Convert.ToDouble(sal); // one way
salary = double.Parse(sal); // another way
Note that these conversions can fail if the string is not in the proper numeric format. double.TryParse could be useful, but it's probably an exception that needs to propogated to your callers when they send an invalid input. With all of that said, I would leave it up to your callers to convert the value to the appropriate type and simply expose the double property. There's no need to complicate matters in your class.
For that matter, for a value that is supposed to represent a salary, you should consider using the more appropriate decimal type. It's tailored for storing financial values.
decimal salary;
// elsewhere
salary = Convert.ToDecimal(sal);
salary = decimal.Parse(sal);
This will get rid of the error you are describing:
public void SetSalary(string sal)
{
salary = Convert.ToDouble(sal);
}
The offending line is
salary = Convert.ToString(sal);
This says: set the salary private field to be whatever the string representation of sal is. But the salary private field is actually a double! You probably want something like
public void SetSalary(string sal)
{
salary = double.Parse(sal);
}
Or, if you don't like to use exceptions for errors, use double.TryParse instead.
salary = Convert.ToString(sal);
You are converting the string sal again to string by ToString? And then you are trying to assign it to a double salary.
// Note that this has been shortened. The compiler will take care of making a backing field for us; we don't need to worry about it.
public double Salary { get; set; }
public Employee()
{
// Only set the default value for Salary in the parameterless constructor.
Salary = 20000.0;
}
public Employee(double salary)
{
// Notice how the parameter names are more verbose.
Salary = salary;
}
public void SetSalary(string value)
{
double salary;
// TryParse allows us to handle errors manually, rather than dealing with (slow) exceptions.
if (double.TryParse(value, out salary))
{
Salary = salary;
}
else
{
// We should really do something other than just throw an exception here, but that's what I'm doing for example purposes.
throw new ArgumentException("Argument must be parsable as a double.", "value");
}
}