Initializing Base Class: declaring a variable twice? - c#

I'm currently reading trough a C# tutorial. Now I came across this:
using System;
namespace RectangleApplication {
class Rectangle {
//member variables
protected double length;
protected double width;
public Rectangle(double l, double w) {
length = l;
width = w;
}
public double GetArea() {
return length * width;
}
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class Tabletop : Rectangle {
private double cost;
public Tabletop(double l, double w) : base(l, w) { }
public double GetCost() {
double cost;
cost = GetArea() * 70;
return cost;
}
public void Display() {
base.Display();
Console.WriteLine("Cost: {0}", GetCost());
}
}
class ExecuteRectangle {
static void Main(string[] args) {
Tabletop t = new Tabletop(4.5, 7.5);
t.Display();
Console.ReadLine();
}
}
}
In the class Tabletop there is cost declared twice. Once as private double cost; and 4 lines later as double cost;
Why is that so?
When removing double cost; the Code still works. When double cost is in the code I can hover over private double cost; and read the message: The field Tabletop.cost is never used". I pretty much can remove either of the cost and the code works fine.
Did they forget to remove one of the declareation or is there a reason behind?
Also, why don't I get an error message like "cost is already defined"?
Here is the Tutorial link

private double cost; is unused and can be removed.
You don't get an error because as John said in the comments, it's in different scopes; one is defined as a field of the class while the other is a local variable. When cost is used, the local variable is accessed. To access the field, this.cost can be used.
class A
{
private int a = 1;
void A()
{
int a = 2;
Console.WriteLine(a); // 2
Console.WriteLine(this.a); // 1
}
}
Note you cannot have multiple local variables with the same name, even in different scopes:
void A()
{
int a = 1;
if(someCondition)
{
int b = 2; // Compiler error: A local variable named 'a' cannot be declared in this scope because it would give a different meaning to 'a', which is already used in a 'parent or current' scope to denote something else
}
}

In fact, in your class Tabletop, the scopes cost is overlapped because there is also a local variable named cost in the method GetCost.
Within the scope of GetCost, when you refer to cost, you are actually referring to the locally scoped object named cost and not the one in the outer scope (the one in the class). When this happens, the cost declared in the outer scope is hidden by the inner scope(in the method).

When defining a variable in a member-scope (in your case within a method) that has the same name as an existing member, you just hide the latter and reference the former.
So in your example:
class Tabletop : Rectangle
{
private double cost;
public Tabletop(double l, double w) : base(l, w) { }
public double GetCost()
{
double cost; // this hides the field
cost = GetArea() * 70;
return cost; // this referts to the variable defined two lines above
}
public void Display()
{
Console.WriteLine("Cost: {0}", cost); // while this refers to the field
}
}
cost from within GetCost will refer to the local variable, while using cost in Display for example will refer to the field.
This is absoluetely fine. However it can yield to confusion and thus unexpected behaviour. This is why some developers tend to use the this-qualifier:
public double GetCost()
{
double cost;
this.cost = GetArea() * 70;
return this.cost;
}
with the qualifier you refer to current instance, making this.cost` an access to your field instead of to the variable.

I think they do forget to remove it.
As why you don't get "cost is already defined" error, it's because the double cost in GetCost() is local (only accessible inside GetCost() method, and will be destroyed from memory after GetCost() method completed), while the private double cost is available to the entire Tabletop class to be accessed and will be kept in memory as long as the Tabletop instance live.

In the class Tabletop there is cost declared twice. Once as private
double cost; and 4 lines later as double cost;
Well private double cost; is a member field for tableTop class whereas other declaration is local to the method body. Why there is a confusion.

Related

C# Abstract methods, readonly properties

I have an assignment (bunch of oop stuff, polymorphism and inheritance) and amongst other things I have to do the following:
I need to add an abstract method to the class Vehicle (called calculateOccupancy()) which has to return the % of the leftover space in a vehicle. I then have to implement that in my derived classes. The issue here is, I have 3 derived classes, two of them have 2 attributes and one has 3. So how do I make my abstract method, so that it can accept 2 or 3 arguments.
I have to add a unchangeable property to the class Person, and the property has to return the first letter of the name and surname, divided by a dot.
namespace Example
{
abstract class Vehicle
{
//class member variables, most likely unnecessary for the questions
private Person driver;
private string vehicleBrand;
private string vehicleType;
private double fuelConsumption;
private double gasTankSize;
private string fuelType;
//the default constructor
public Vehicle()
{}
//The abstract method from question 2
// how to make it so that it wont error when I need to
//put in 3 variables instead of two, meaning, how would I add int c
public abstract double calculateOccupancy (int a, int b);
//The derived class that implements the method
class Bus : Vehicle
{
private int allSeats;
private int allStandingSeats;
private int busPassengers; //the number of passengers
//the constructor
public Bus (int a, int b, int c)
{
allSeats=a;
allStandingSeats=b;
busPassengers=c;
}
//the abstract method
// needs to take in int b (standing seats)
public override double calculateOccupancy(int a, int c)
{
//this code calculates the leftover space in the vehicle
double busSpace=(busPassengers*100) / allSeats;
return busSpace;
//same code for the leftover standing space (int c)
}
}
}
class Person
{
protected string name;
protected string lastName;
//question 1
//properties for char gender
protected char gender;
//question 3
protected readonly string initials;
//the code errors, at the get/set
public char Gender
{
get{ return gender; }
set {gender=value;}
}
/*and the property im not sure how to make
public string Initials{}
*/
}
I hope the comments add some clarity, rather than confusion, thank you for your help everybody.
Assumption going forward - I threw some of your variable names into Google Translate and it seems to be Slovenian. I'm assuming that going forward which helped me make some clarity of what your code does.
1) Replace - If you already have a variable that is a char representing spol then I believe you're supposed to use the new enum type you are to create to represent it.
public enum Spol
{
Moski = 0,
Zenska = 1
}
Change:
protected char spol;
public char Spol
{
get{ return spol; }
set {spol=value;}
}
To: public Spol Spol { get; set; }
2) Defaults & Conditions - Use int c = 0 as your 3rd parameter and use a formula/algorithm that ignores it if it is the default value.
3) Getters - This property doesn't have a setter and therefore cannot be changed (directly).
public string GiveThisAName
{
get
{
if (String.IsNullOrWhiteSpace(ime))
{
return null;
}
if (String.IsNullOrWhiteSpace(priimek))
{
return null;
}
return ime[0] + '.' + priimek[0];
}
}
Notes
1) Heavily recommend making the parameters of your capacity function (i.e. izracunajZasedenost(int a, int b)) to be named something useful (i.e. a name descriptive of what they do) other than a and b.
2) For the record, #1 seems more like an appropriate question for your instructor, teacher, or whoever gave you this assignment.
Give the "optional" values a value when you create the abstract method
public abstract double izracunajZasedenost (int a = -1, int b = -1)
{
if (a == -1){
//do method with ignoring a
}
};

C# Objects and Constructors best practices

namespace Area
{
public class Rectangle
{
private double length;
private double width;
public Rectangle() { }
public Rectangle(double length, double width)
{
this.Length = length;
this.Width = width;
}
public double Length
{
get
{
return length;
}
set
{
length = value;
}
}
public double Width
{
get
{
return width;
}
set
{
width = value;
}
}
public double getArea()
{
return width * length;
}
public double getPerimeter()
{
return 2 * width + 2 * length;
}
public double getDiagonal()
{
return Math.Sqrt(Math.Pow(width, 2) + Math.Pow(length, 2));
}
I want to make sure I am using best practices with C# Objects. Please use the above example for reference.
1. Is it necessary that I type the first empty Constructor? In class the Instructor always did on each program but never really gave an answer as to why.
public Rectangle() { }
2. Inside my Custom Constructor Visual Studio generates it like this:
this.Length = length;
I know that the "this" keyword is not necessary the way it is typed, but in class the instructor sometimes changed it to lowercase like this:
this.length = length;
But sometimes he didn't change it. Which way is best practices?
And is the left side the actual Property? And then the right side is the field?
So it is, Property equals field?
3. And finally, in this case cant I just type my properties as:
public string Length { get; set; }
instead of the way Visual Studio generates with the return and value.
Sorry for the long post, I am tired of getting different answers at school and want one final answer on this, thanks.
I would suggest that your class look like this:
public class Rectangle
{
public Rectangle(double length, double width)
{
this.Length = length;
this.Width = width;
}
public double Length { get; set; }
public double Width { get; set; }
public double Area { get { return this.Width * this.Length; } }
public double Perimeter { get { return 2.0 * (this.Width + this.Length); } }
public double Diagonal { get { return Math.Sqrt(Math.Pow(this.Width, 2.0) + Math.Pow(this.Length, 2.0)); } }
}
See here for why you might want a blank constructor. To summarize, adding a non blank constructor will stop the compiler from generating a blank one for you (the compiler assumes that if you wanted it, you would have defined it with the other constructors you wrote). Some things, like serialization, will not work without a blank constructor, so that's a reason you might want to add one.
In my career, I've mostly seen people avoid using this in constructors. Maybe avoid isn't the right word, but unless it's unclear, they just didn't bother to put it there. This is probably too minor an issue to lose any sleep over.
UPDATE based on some of your comments
When you write
public Rectangle(double length, double width)
{
Length = length; //parameter length assigned to field length by virtue of property Length
}
you are assigning the parameter length to the property Length, which itself assigns the passed in value to the length private field. Since C# is case sensitive, Length and length aren't confused in any scenario, and you don't need to specify the this keyword.
Inside a method with a parameter called length, the language is assuming that you are referring to the parameter of the method when you type length. So if you try to do something like this:
public Rectangle(double length, double width)
{
length = length; //warning: Assignment made to same variable; did you mean to assign to something else
}
The compiler doesn't try and assume that you are assigning the property to the field, and this is just assigning the length parameter to itself. In this case, you would use the this keyword to tell the compiler that you want to assign the parameter length to the private field length, like this:
public Rectangle(double length, double width)
{
this.length = length; //no warning
}
END UPDATE
Yes, you could declare the property as just Property {get;set;}. This feature is only from C# 3.0 and is called auto-implemented properties (see this link). Before that you had to provide the implementation yourself.
I changed my class to this:
public class Rectangle
{
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
public double Length { get; set; }
public double Width { get; set; }
public double getArea()
{
return Width * Length;
}
public double getPerimeter()
{
return 2 * Width + 2 * Length;
}
public double getDiagonal()
{
return Math.Sqrt(Math.Pow(Width, 2) + Math.Pow(Length, 2));
}
}
If anyone has any other feedback on anything above that you recommend to change please give it, I catch on very fast and want to learn the correct way.

Error CS1014: A get or set accessor expected

using System;
//Find the square root of a number for 10 values from user
class forLoop
{
static void Main
{
double x;
for(int i=10; i>0 && x>=0; i--)
{
Console.WriteLine("You have {0} remaining calculations left", i);
Console.Write("Please enter a positive number: ");
x = double.Parse((Console.ReadLine());
x = Math.Sqrt(x);
Console.WriteLine("The square root is {0}", x);
Console.WriteLine("");
}
Console.WriteLine("You have 0 remaining calculations left");
}
}
I need help on this C# problem: Why does the error: "A get or set accessor expected" come up at compile time?
You missed the () in method declaration. Thus, the compiler thinks at some level that you're declaring a Property (albeit it would then throw an error about the void type), not a Method
// Property
public int Property
{
get { return _field; }
set { _field = value; }
}
// Property, albeit a get-only property
public int Property => _field;
// Method
public int Method()
{
return _field;
}
// Method
public int Method() => _field;
UPDATE: Since this is still being seen, I've updated the example values to better reflect their underlying types, and included examples of expression bodies introduced with C# 6
You need parentheses (()) in the method declaration.
Parentheses is required to differentiate a method from a property that requires the get/set syntax

Simple Method Output Process

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

Meaning of "this" for a struct (C#)

According to MSDN (Section 11.3.6 of the C# spec):
Within an instance constructor of a
struct, this corresponds to an out
parameter of the struct type, and
within an instance function member of
a struct, this corresponds to a ref
parameter of the struct type. In both
cases, this is classified as a
variable, and it is possible to modify
the entire struct for which the
function member was invoked by
assigning to this or by passing this
as a ref or out parameter.
I don't get it. How is this different for a struct than for a class? Code examples are appreciated
Eric Lippert had a fabulous post on mutating readonly structs a while back that will really help clarify the issue for you. There's even a code example, and a quiz!
The salient point is that structs obey value semantics and classes do not and so this must mean something different for the two. this is readonly for a class, but not for a struct. The following code is legal
struct Point {
public int x;
public int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void DoGoTime() {
GoTime(ref this);
}
public static void GoTime(ref Point p) {
p.x = 100;
p.y = 100;
}
}
but is not if "struct" is replaced by "class."
When you're dealing with structs, you're dealing with value types.
In a class, "this" is a reference to the current instance. This lets you mutate the class instance by setting properties/fields on the class.
However, if you're in a struct, things act differently. When you're in a struct's method, "this" lets you mutate the struct. However, if you're using this in a method, you're almost always dealing with a copy of the "original" struct.
For example:
struct Test
{
int i;
void Mutate() {
this.i += 1;
}
}
When you use this:
void MutateTest(Test instance)
{
instance.Mutate();
}
{
Test test = new Test();
test.i = 3;
Console.WriteLine(test.i); // Writes 3
test.Mutate(); // test.i is now 4
Console.WriteLine(test.i); // Writes 4
MutateTest(test); // MutateTest works on a copy.. "this" is only part of the copy itself
Console.WriteLine(test.i); // Writes 4 still
}
Now, the stranger part - this is valid, and what that quote was saying:
struct Test
{
public Test(int value)
{
this.i = value;
}
int i;
void Mutate(int newValue) {
this = new Test(newValue); // This wouldn't work with classes
}
}
///
{
Test test = new Test();
test.i = 3;
Console.WriteLine(test.i); // Writes 3
test.Mutate(4);
Console.WriteLine(test.i); // Writes 4
Jason's answer and Eric's post show one aspect of this which is interesting... but there's another which is even more alarming:
You can reassign this within a method, even if the type is otherwise immutable.
To demonstrate it, we'll use a struct which is stored in a non-readonly variable, but which contains a readonly field:
using System;
public struct LooksImmutable
{
private readonly int value;
public int Value { get { return value; } }
public LooksImmutable(int value)
{
this.value = value;
}
public void GoCrazy()
{
this = new LooksImmutable(value + 1);
}
}
public class Test
{
static void Main()
{
LooksImmutable x = new LooksImmutable(5);
Console.WriteLine(x.Value);
x.GoCrazy();
Console.WriteLine(x.Value);
}
}

Categories

Resources