When I output the following code on the console, I would get the "Age is wrong" line followed by a '0' (when I input the dog's Age to be -10). I would only want to display the 'Age is wrong' line.
Program Class
class Program
{
static void Main()
{
Animal dog = new Animal();
dog.Age = -10;
Console.WriteLine(dog.Age);
}
}
Animal Class
class Animal
{
private int age;
private string color;
public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
Console.WriteLine("Age is wrong");
}
else
{
age = value;
}
}
}
}
Only log the Age when it is not zero is what you want, this is what you should do:
if(dog.Age != 0)
{
Console.WriteLine(dog.Age);
}
Your Program class doesn't know how to detect that the age was wrong - so it just outputs the current age value (0).
You could have a method that returns a boolean, indicating whether setting the age has succeeded:
public int Age { get { return age; } } // no setter
public bool SetAge(int newAge)
{
if (newAge < 0)
{
Console.WriteLine("Wrong age: " + newAge);
return false;
}
age = newAge;
return true;
}
....
if (dog.SetAge(-10))
{
Console.WriteLine("Age successfully set to " + dog.Age);
}
Or you could rely on exception handling:
public int Age
{
get { return age; }
set
{
if (value < 0) throw new Exception("Invalid age: " + value);
age = value;
}
}
...
try
{
dog.Age = -10;
Console.WriteLine(dog.Age);
}
catch (Exception ex)
{
Console.WriteLine("Error setting age: " + ex.Message);
}
Since you are already writing to the console in the setter of the property, you could simply move all the writing into the setter block. For example like this:
class Program
{
static void Main()
{
Animal dog = new Animal();
dog.Age = -10;
}
}
class Animal
{
private int age;
private string color;
public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
Console.WriteLine("Age is wrong");
}
else
{
age = value;
Console.WriteLine(age);
}
}
}
}
Related
//File Main.cs
using BasicClasses;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Profile p = new Profile("16");
p.PrintProfile();
}
}
}
//File Profile.cs
namespace BasicClasses
{
class Profile
{
//Fields
public string age;
//Constructors
public Profile(string age)
{
this.age = age;
}
//Properties
private string Age
{ get { return this.age; }
set
{
if (value.Length > 0)
{
if (Int32.Parse(value) >= 18)
{ Age = value; }
else
{ Age = "Invalid Age"; }
}
else
{ Age = "Not Defined"; }
}
}
//Methods
public void PrintProfile()
{
Console.WriteLine($"Age :: {Age}");
}
}
}
//Output
//Age :: 16
My issue is with the variable 'Age'. The output should be "Age :: Invalid Age". I defined 'this.age' in a constructor and used that variable in the property of 'Age'. However the property is outputting the exact same thing that was entered in the constructor seemingly Skipping the Property of 'Age'.
You have some problems.
1 - Its attribution in the constructor, by directly calling its field "this.age", does not pass through the validation created in its property.
public Profile(string age)
{
this.Age = age;
}
2 - Your validation will return an Exception, because when parsing the value "Invalid Age" you will get an error. You should set the Field value to avoid this:
private string Age
{
get { return this.age; }
set
{
if (value.Length > 0)
{
if (Int32.Parse(value) >= 18)
{ this.age = value; }
else
{ this.age = "Invalid Age"; }
}
else
{ this.age = "Not Defined"; }
}
}
Another piece of advice I would give you would be to change your validation to:
if (int.TryParse(value, out var integerValue) && integerValue >= 18)
{ this.age = integerValue.ToString(); }
Thus avoiding a possible exception.
Hope I helped, have a good journey.
The button function, should take whatever text is in the combo box and place it within sleeper.traintype
private void Btn_Apply_Click(object sender, RoutedEventArgs e)
{
try
{
sleeper.trainType = CmbBox_TrainType.Text;
if (CmbBox_TrainType.Text == "Sleeper")
{
// instantiate the sleeper train
sleeper.trainType = CmbBox_TrainType.Text;
}
}
My sleeper train class (inheriting from overall train class)
public class Sleeper : Train
{
private string _intermediate, _intermediate1, _intermediate2, _intermediate3;
private bool _cabin;
public string intermediate
{
get
{
return _intermediate;
}
set
{
_intermediate = value;
}
}
public string intermediate1
{
get
{
return _intermediate1;
}
set
{
_intermediate1 = value;
}
}
public string intermediate2
{
get
{
return _intermediate2;
}
set
{
_intermediate2 = value;
}
}
public string intermediate3
{
get
{
return _intermediate3;
}
set
{
_intermediate3 = value;
}
}
The train class:
public class Train
{
private string _trainID, _departureDay, _departureStation, _destinationStation, _departureTime, _trainType;
private bool _firstClass;
public string timePunctuation = ":";
public string dayPunctuation = "/";
public string trainID
{
get
{
return _trainID;
}
set
{
// check if the vlaue has letters & numbers and that the length is correct
if(value.Length == 4 && Regex.IsMatch(value, "[A-Z][0-9]"))
{
_trainID = value;
}
else
{
throw new FormatException("That train ID is not valid! (Example: AA11)");
}
}
}
public string departureDay
{
get
{
return _departureDay;
}
set
{
if(value.Length == 0)
{
throw new FormatException("You need to choose a departure day!");
} else
{
_departureDay = value;
}
}
}
public string departureTime
{
get
{
return _departureTime;
}
set
{
if(value.Length != 5 || value.Contains(timePunctuation) == false)
{
throw new FormatException("The time must be in this format: (11:11 or 03:22)");
} else
{
_departureTime = value;
}
}
}
public string departureStation
{
get
{
return _departureStation;
}
set
{
if(value.Length == 0)
{
throw new FormatException("You must enter a departure station!");
} else
{
_departureStation = value;
}
}
}
public string destinationStation
{
get
{
return _destinationStation;
}
set
{
if(value.Length == 0)
{
throw new FormatException("You must enter a destination!");
} else
{
_departureStation = value;
}
}
}
public string trainType
{
get
{
return _trainType;
}
set
{
value = _trainType;
}
}
}
I'm using a combobox with three options "Sleeper", "Stopping" and "Express". When using breakpoints next to sleeper.trainType = CmbBox_TrainType.Text; it creates my class but states that my sleeper.trainType variable is null. But it says that
CmbBox_TrainType = "Sleeper"
Instantiate sleeper at the start with Sleeper sleeper = new Sleeper();
but have also tried to put it in the if and just before sleeper.trainType = CmbBox_TrainType.Text;
I have a problem with a class that I wrote. When I try to call it I get an exception. See the code below for more clarity.
I have the class:
using System;
using System.Data;
namespace People
{
class Person
{
// Auto prop + field
public string Name
{
get { return this.Name; }
private set
{
if (string.IsNullOrEmpty(value))
{
throw new NoNullAllowedException("Name is mandatory");
}
else
{
this.Name = value;
}
}
}
// Auto prop + field
public int Age
{
get { return this.Age; }
private set
{
if (value <= 0 || value > 100)
{
throw new Exception("Age must be between 1 and 100");
}
else
{
this.Age = value;
}
}
}
// Auto prop + field
public string Email
{
get { return this.Email; }
private set { this.Email = value; }
}
// Constructor 1
public Person(string name, int age, string email)
{
this.Name = name;
this.Age = age;
this.Email = email;
}
// Constructor 2
public Person(string name, int age) : this(name,age,"")
{
}
// Write to console
public override string ToString()
{
return string.Format("Name: {0} \nAge: {1} \nEmail: {2}" ,Name,Age,Email);
}
}
}
And when I call this class:
Person someone = new Person("First Someone",51,"someone#gmail.com");
Console.WriteLine(someone);
I get:
Process is terminated due to StackOverflowException.
I can't see the problem.
Thank you in advance.
The problem is that when you try to get or set any of the properties, say, Name, there is a code path that calls the setter of the same property:
public string Name
{
get { return this.Name; } // <<<<====== HERE
private set
{
if (string.IsNullOrEmpty(value))
{
throw new NoNullAllowedException("Name is mandatory");
}
else
{
this.Name = value; // <<<<==== HERE
}
}
}
this.Name means "call getter/setter of Name with the value of value". This creates infinite recursion, causing stack overflow.
To implement properties with conditions like that you need to define fields that store the actual data. A common approach is to make these fields private, and name them with the same name as the property, except the first letter should not be capitalized:
private string name; // <<<<==== Add this
public string Name
{
get { return name; } // <<<<====== change
private set
{
if (string.IsNullOrEmpty(value))
{
throw new NoNullAllowedException("Name is mandatory");
}
else
{
name = value; // <<<<==== change
}
}
}
change
get { return this.Name; }
to
get;
the same goes for the Age property.
This is because this.Name is using the get method you are overriding, thus creating the glorious StackOverflowException! If you need a field for name and age you have to create one yourself like:
private string name;
public string Name
{
get { return this.name; }
private set
{
if (string.IsNullOrEmpty(value))
{
throw new NoNullAllowedException("Name is mandatory");
}
else
{
this.name = value;
}
}
}
Trying to learn to program and once again losing all confidence because I think I've internalised a simple concept but something seemingly extraordinary is happening or it is just flying right over my head.
When I run the program I get a StackOverFlowException if I access the property by assigning a string to FirstName or SecondName
My Customer Class:
class Customer : ICustomer
{
public string FirstName
{
get
{
return FirstName;
}
set
{
FirstName = value;
}
}
public string fName
{
get
{
return fName;
}
set
{
fName = value;
}
}
public string SecondName
{
get
{
return SecondName;
}
set
{
SecondName = value;
}
}
public string sName
{
get
{
return sName;
}
set
{
sName = value;
}
}
public int ID
{
get
{
return ID;
}
set
{
ID = value;
}
}
public int mId
{
get
{
return mId;
}
set
{
mId = value;
}
}
public int GetID()
{
return mId;
}
public void SetID(int id)
{
mId = ID;
}
public void SetName(string fName, string sName)
{
fName = FirstName;
sName = SecondName;
}
}
and the main program
class Program
{
/// <summary>
/// Create unique string code based off current date and time.
/// </summary>
/// <returns>code string</returns>
static string generateUniqueCode()
{
string characters = "abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
string ticks = DateTime.UtcNow.Ticks.ToString();
var code = "";
for (var i = 0; i < characters.Length; i += 2)
{
if ((i + 2) <= ticks.Length)
{
var number = int.Parse(ticks.Substring(i, 2));
if (number > characters.Length - 1)
{
var one = double.Parse(number.ToString().Substring(0, 1));
var two = double.Parse(number.ToString().Substring(1, 1));
code += characters[Convert.ToInt32(one)];
code += characters[Convert.ToInt32(two)];
}
else
code += characters[number];
}
}
return code;
}
/// <summary>
/// Creates unique integer code based off current date and time.
/// </summary>
/// <returns>integer code</returns>
static int generateUniqueCode(int seed)
{
string characters = "0123456789";
Random randInt = new Random(seed);
var ticks = randInt.Next();
int code = 0;
for (var i = 0; i < characters.Length; i += 2)
{
if ((i + 2) <= ticks)
{
var number = ticks;
if (number > characters.Length - 1)
{
var one = double.Parse(number.ToString().Substring(0, 1));
var two = double.Parse(number.ToString().Substring(1, 1));
code += characters[Convert.ToInt32(one)];
code += characters[Convert.ToInt32(two)];
}
else
code += characters[number];
}
}
return code;
}
static void Main(string[] args)
{
Customer customer = new Customer();
int generatedIntCode = generateUniqueCode(1);
customer.FirstName = "Conor";
customer.SecondName = "MacFirbhisigh";
customer.SetID(generatedIntCode);
Console.WriteLine("{0}, {1} {2}", customer.ID, customer.FirstName, customer.SecondName);
//Console.ReadKey();
}
}
In the getter and setter of FirstName (and all others), you are calling the same property over and over again. The endless loop you created will result in a StackOverflowException.
If you don't want to add custom logic to your properties, just use auto-implemented properties:
public string FirstName
{
get;
set;
}
If you did want to implement the property on your own, creating your own backing fields, this is what it should look like (this is effectively the same as what the above code would generate):
private string firstName; // backing field
public string FirstName
{
get
{
return this.firstName; // return the backing field
}
set
{
this.firstName = value; // set the backing field
}
}
You left out a few important parts
Firstly, you always need to declare you variables,
public - for outside get and set, thus no need for the get-set methods.
private - get/set methods are necessary for data retrieval modification.
Also, see the SetName method.
Hope it helps :p
This should do the trick:
class Customer : ICustomer
{
private string firstName;
private string name;
private string secondName;
private string sName;
private int iD;
private int mId;
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
}
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string SecondName
{
get
{
return secondName;
}
set
{
secondName = value;
}
}
public string SName
{
get
{
return sName;
}
set
{
sName = value;
}
}
public int ID
{
get
{
return iD;
}
set
{
iD = value;
}
}
public int MId
{
get
{
return mId;
}
set
{
mId = value;
}
}
public void SetName(string fName, string sName)
{
FirstName = fName;
SecondName = sName ;
}
}
i was need to write 2 methods in my student class which do the following
hasPassed() Should return True if the student has a year mark >= 40 or
false if the marks is <40
toString() Should return a single string containing a summary of the
student details held within the class
e.g.
“12345 Basil Fawlty, 23/08/1946”
here's the code i have for the above to methods, is what i have correct for what its asking for the above?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CourseWork
{
public class Student
{
private static string firstname;
private string secondname;
private string dateofbirth;
private string course;
private int matricnumber;
private double yearmark;
public bool hasPassed()
{
if (yearmark >= 40)
return true;
else
return false;
}
public void toString()
{
firstname = "Basil";
secondname = "Fawlty";
dateofbirth = "23/08/1946";
course = "MA Hotel Management";
matricnumber = 12345;
yearmark = 55;
}
public Student()
{
}
public string FirstName
{
get { return firstname; }
set { firstname = value; }
}
public string SecondName
{
get { return secondname; }
set { secondname = value; }
}
public string DateOfBirth
{
get { return dateofbirth; }
set { dateofbirth = value; }
}
public string Course
{
get { return course; }
set { course = value; }
}
public int MatricNumber
{
get { return matricnumber; }
set
{
if (value <= 99999 && value >= 10000)
{
matricnumber = value;
}
else
{
Console.WriteLine("Invalid Matric Number: {0}", value);
}
matricnumber = value;
}
}
public double YearMark
{
set
{
if (value <= 100 && value >= 0)
{
yearmark = value;
}
else
{
Console.WriteLine("Invalid Year Mark: {0}", value);
}
yearmark = value;
}
}
}
i then need the above methods to be used in a get button that does the following
Get: Uses the values of the Student class methods to update the text boxes. The
Student.hasPassed() method should be used to update the pass/fail label. The
Student details summary should be updated by using Student.toString ().
but I'm having trouble coding it and i cant seam to call hasPassed() method or toString() method from my student class
so I've doing something wrong but cant see what it is
any ideas how to go about fixing this?
In order the methods to be visible, you need to create an instance of the class Student. ex,
Student _student = new Student();
bool _x = _student.hasPassed();
if you want the members to be access without instantiating, make the member static,
public static bool hasPassed()
{
if (yearmark >= 40)
return true;
else
return false;
}
but bear in mind that static members cannot see non-static members. In that case, it won;t compile because yearmark cannot be found.