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");
}
}
Related
I am trying to understand a concept and I'm not sure how to go about it. I would really appreciate some help.
What I am trying to do is pull data from a comma separated text file and then use what I pulled to create another object. For example, I want to determine the weeklyWage for a 40 hour week using the hourly wage. If I pulled in the hourly wage from the text file with a { get; set; } is there a way to then say "weeklyWage = hourlyWage * 40"?
public class employee
{
public double hourlyWage { get; set; }
public double weeklyWage = hourlyWage * 40;
}
error: field initializer cannot reference the non-static field
The issue you have here is related to the fact that compiler is not aware what is the value of hourlyWage property at the moment field weeklyWage is inializing; so it gives you an error. It (value for weeklyWage) is suppossed to be set from your code, while parsing text file or dynamically calculated. So 2 easy options you to have:
You might use setters of hourlyWage:
public class employee
{
// This is "backing field" for hourly wage
private double _hourlyWage;
// And this is actual property, where business logic happens
public double hourlyWage
{
get
{
return _hourlyWage;
}
set
{
// Set both _hourlyWage and weeklyWage at once
_hourlyWage = value;
weeklyWage = _hourlyWage * 40;
}
}
// Public for get, private for set (r
public double weeklyWage { get; private set; }
}
Or you might want to use dynamic getter:
public class employee
{
public double hourlyWage{get;set;}
public double weeklyWage { get { return hourlyWage * 40; } }
// "modern" getter syntax would look this way:
// public double weeklyWage => hourlyWage * 40;
// Still used "old" syntax for being more expressive.
// The choice is yours.
}
I would prefer first approach, as value for weeklyWage is calculated once, at the moment hourlyWage is set.
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.
I have a basic class with this method including
public class Account
{
//MEMBERS
private int acctNo;
protected double balance;
public double deposit;
// CONSTRUCTORS
public Account() //member intitilization
{
acctNo = 54534190;
balance = 7500;
deposit= 1500;
}
//PROPERTIES
public int AcctNo
{
get {return acctNo; }
set {acctNo = value; }
}
public double Balance
{
get { return balance; }
set { balance = value; }
}
public double Deposit
{
get {return deposit; }
set {deposit = value; }
}
public virtual double getDeposit (double amount)
{
double transactionAmt=0.00;
if (amount>0)
{
balance+=amount;
transactionAmt= amount;
}
return transactionAmt;
}
Now in my actual program I am trying to output this method. What would my writeline look like?
I tried to write this:
static void Main(string[] args)
{
Console.WriteLine("CREATING ACCOUNT");
Account myAcctDefault = new Account();
DumpContents(myAcctDefault);
Pause();
}
static void DumpContents(Account account)
{
Console.WriteLine(" output {0}", account.getDeposit());
}
I am getting an error saying:
no overload for method 'getDeposit' takes 0 arguments.
What am I doing wrong, am I trying to output this method incorrect?
Any help, insight or suggestions would be extremely helpful.
I am new to c# as I'm sure you can tell. What is the proper process to output a method in this context?
I am getting an error saying "no overload for method 'getDeposit' takes 0 arguments". What am I doing wrong
Exactly what it says. Here's your method call:
Console.WriteLine(" output {0}", account.getDeposit());
... and here's the method declaration:
public virtual double getDeposit (double amount)
Note how the method declares a parameter - but you're not providing an argument. Either you need to get rid of the parameter, or you need to add an argument to the method call. Or you need to change to using a different method - one which doesn't change the balance of the account. (It seems unlikely that you want to do that in this case.) Perhaps you should add a Balance property:
// Please note that this should probably be decimal - see below
public double Balance { get { return balance; } }
Then call it with:
Console.WriteLine(" output {0}", account.Balance);
Additionally:
For financial quantities, it's generally better to use decimal than double. Read my articles on decimal floating point and binary floating point for more information.
Your getDeposit method doesn't follow .NET naming conventions, where (at least public) methods are named in PascalCase, with a leading capital letter
Your getDeposit method is oddly named as it isn't "getting" a deposit - it's making a deposit (and returning the balance)
Your getDeposit method always returns the value passed into it, unless it's negative. That seems odd to me - if it's going to return anything, shouldn't it return the balance?
Your getDeposit method silently ignores negative deposits. I'd expect this to throw an error, as trying to make a negative deposit indicates a programming error IMO.
Your getDeposit method takes one argument that you are not passing to it. Depends what you want to achieve either pass a value to method:
static void DumpContents(Account account)
{
double deposit = 1000;
Console.WriteLine(" output {0}", account.getDeposit(deposit));
}
or remove this argumentparameter from the method signature.
//You have to pass a double value into the method, because there is only one method
//and wants a double paramater:
//this is what you created:
public double getDeposit(double amount) // <-
{
double transactionAmt = 0.00;
if (amount > 0)
{
balance += amount;
transactionAmt = amount;
}
return transactionAmt;
}
//This how you should call it:
static void DumpContents(Account account)
{
Console.WriteLine(" output {0}", account.getDeposit(34.90)); //<-
}
I am learning C#, and am learning about making fields private to the class, and using Getters and Setters to expose Methods instead of field values.
Are the get; set; in Method 1 and Method 2 equivalent? e.g. is one a shorthand of the other?
class Student
{
// Instance fields
private string name;
private int mark;
// Method 1
public string Name { get; set; }
// Method 2
public int Mark
{
get { return mark; }
set { mark = value; }
}
}
Finally, would Method 2 be used when you want to for example perform a calculation before getting or setting a value? e.g. converting value to a percentage or perform validation? e.g.
class Student
{
// Instance fields
private string name;
private double mark;
private int maxMark = 50;
// Method 1
public string Name { get; set; }
// Method 2
public double Mark
{
get { return mark; }
set { if ( mark <= maxMark ) mark = value / maxMark * 100; }
}
}
Yes, the Method2 is the way to go when you have a custom getter and setter function. By default when you use Method1, there will be a default private property handled internally. Please refer this URL for more details.
Sample:
string _name;
public string Name
{
get => _name;
set => _name = value;
}
Yes, Method 1 is a shortcut to Method 2. I suggest using Method 1 by default. When you need more functionality, use Method 2. You can also specify different access modifiers for get and set.
Hello fellow stackoverflow members!
I'm very new to the C# language transfer from Java, Obj-C.
It looks pretty same as Java, but I have trouble issue in very simple thing.
I have created two individual class files, Class-A and Class-Human.
Specification for Class-A
it contains the static main method declared.And I've tried to create the new instance of Class-Human.
public static void main(String args[])
{
Human human = new Human("Yoon Lee", 99);
int expected = human.getNetID; //<-gets the error at this moment.
}
Specification for Class-Human
namespace Class-A
{
public class Human
{
public String name;
public int netId;
public Human(String name, int netId)
{
this.name = name;
this.netId = netId;
}
public int getNetID()
{
return netId;
}
}
Why can't copy over into local variable?
The compiler prompts me the error of
'Cannot convert method group of 'getNetID' delegate blah blah'
Thank you.
Change the method-call to:
int expected = human.getNetID();
In C#, method-calls require parantheses () containing a comma-separated list of arguments. In this case, the getNetID method is parameterless; but the empty parantheses are still required to indicate that your intention is to invoke the method (as opposed to, for example, converting the method-group to a delegate-type).
Additionally, as others have pointed out, there is a mismatch betweem the return-type of the method and the variable you're assigning its value to, which you're going to have to resolve somehow (change both the field-type and method return-type to int / parse the string as an integer, etc.).
On another note, C# natively supports properties for getter-setter semantics, so the idiomatic way of writing this would be something like:
//hyphens are not valid in identifiers
namespace ClassA
{
public class Human
{
// these properties are publicly gettable but can only be set privately
public string Name { get; private set; }
public int NetId { get; private set; }
public Human(string name, int netId)
{
this.Name = name;
this.NetId = netId;
}
// unlike Java, the entry-point Main method begins with a capital 'M'
public static void Main(string[] args)
{
Human human = new Human("Yoon Lee", 99);
int expected = human.NetId; // parantheses not required for property-getter
}
}
}
You're trying to use a method as if it's a property. You need parenthesis and to convert the string to int, or just make getNetID return an int.
I think you meant:
public int getNetID()
{
return netId;
}
Or better still, use automatic properties:
public int NetId {get; private set;} //Notice Making N in Net capital
And then:
int expected = human.getNetID();
This will do the trick (-:
It should be human.getNetID()
Edit: And yes, as Oren says - you should change your netId getter to return int. I assume that is what you want to do.
I see that netId is integer.
getNetID() return type is string.
return type is not matching.
netID is declared as an Int:
public int netId;
but your function getNetID returns a string:
public String getNetID()
Therefore, the body of getNetID makes no sense when it tried to return an int as a string:
return netId;
Human human = new Human("Yoon Lee", 99);
int expected = human.getNetID(); //<-gets the error at this moment.
you need to add parentheses after the method call.
The way you have it right now you are fetcing the function itself.