How to set a read only property with a set accessor - c#

I have created a class that has an automatic property for an int variable called BagsOfFeed. I added an automatic property to prevent the value from being changed from outside the class.
I use another property that calculates the BagsOfFeed only when the NumberOfCows property is set.
I have come across problem when I make BagsOfFeed readonly it prevents the NumberOfCows property from assigning a value to BagsOfFeed.
here is the class Code
namespace cow_calculator1
{
class Farmer
{
public Farmer(int numberOfCows, int feedMultiplier)
{
this.feedMultiplier = feedMultiplier;
NumberOfCows = numberOfCows;
}
public int BagsOfFeed { get { return BagsOfFeed; } }
private int feedMultiplier;
public int FeedMultiplier
{
get
{
return feedMultiplier;
}
}
private int numberOfCows;
public int NumberOfCows
{
get
{
return numberOfCows;
}
set
{
numberOfCows = value;
BagsOfFeed = numberOfCows * FeedMultiplier;
}
}
}
}
this is the form Code
namespace cow_calculator1
{
public partial class Form1 : Form
{
Farmer farmer;
public Form1()
{
InitializeComponent();
farmer = new Farmer(15, 30);
}
private void calculate_Click(object sender, EventArgs e)
{
Console.WriteLine("I need {0} bags of feed for {1} cows", farmer.BagsOfFeed, farmer.NumberOfCows);
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
farmer.NumberOfCows = (int) numericUpDown1.Value;
}
}
}
this is the error
Error 1 Property or indexer 'cow_calculator1.Farmer.BagsOfFeed' cannot be assigned to -- it is read only ( "Line 38" "Column 17" cow calculator1)

You can scope a setter to be private, and remove the return value.
public int BagsOfFeed { get; private set; }
Which is roughly equivalent to
private int bagsOfFeed;
public int BagsOfFeed {
get { return bagsOfFeed; }
private set { bagsOfFeed = value; }
}
Or in the second format you could just set the private backing store directly.

Related

how to cast a generic type to another type?

As shown in the first class displayed, I need to cast Activité to Réunion (Réunion extends Activité) but the compiler tells me that I can't. Why? I'll put a scheme so you can better understand my classes structure and also all my other classes. Thank you.
class Employé<T>
{
private string nom;
private Local bureau;
private LinkedList<Activité<T>> activités;
public Employé(string nom, Local bureau)
{
this.nom = nom;
this.bureau = bureau;
}
public void AjouteActivité(params Activité<T>[] activités)
{
foreach(Activité<T> activité in activités)
{
if (activité as Réunion != null)
// here's the problem !!! ((Réunion)activité).EmployéConvoqués = activité;
}
}
}
Here's the scheme of my classes structure:
And here are the other classes:
abstract class Activité<T>
{
private string label;
private DateTime début, fin;
private T lieu;
private readonly int id;
private static int CPT = 0;
public Activité(string label, DateTime début, DateTime fin, T lieu)
{
this.label = label;
this.début = début;
this.fin = fin;
this.lieu = lieu;
this.id = ++CPT;
}
public override string ToString()
{
return $"{id} : {label}(de {début} à {fin}) - {DescriptionLieu()}";
}
public double Duree()
{
return fin.Subtract(début).TotalMinutes;
}
public int Id
{
//tester get; seulement
get
{
return id;
}
}
public T Lieu
{
get
{
return lieu;
}
}
public abstract string DescriptionLieu();
}
class ActivitéExtérieure : Activité<string>
{
public ActivitéExtérieure(string label, DateTime début, DateTime fin, string lieu) : base(label,début,fin,lieu) { }
public override string DescriptionLieu()
{
return Lieu;
}
}
class ActivitéInterne : Activité<Local>
{
public ActivitéInterne(string label, DateTime début, DateTime fin, Local lieu) : base(label,début,fin,lieu)
{
lieu.AjouteActivité(this);
}
public override string DescriptionLieu()
{
return $"local :: {Lieu.NumComplet}";
}
}
class Employé<T>
{
private string nom;
private Local bureau;
private LinkedList<Activité<T>> activités;
public Employé(string nom, Local bureau)
{
this.nom = nom;
this.bureau = bureau;
}
public void AjouteActivité(params Activité<T>[] activités)
{
foreach(Activité<T> activité in activités)
{
if (activité as Réunion != null)
((Réunion)activité).EmployéConvoqués = activité;
}
}
}
class Local
{
private int etage;
private int numero;
private bool possedeWifi;
private Dictionary<int, ActivitéInterne> historiquesActivités;
public int Numero
{
get
{
return numero;
}
set
{
if (value < 0 || value > 99)
throw new IndexOutOfRangeException();
else
numero = value;
}
}
public int NumComplet
{
get
{
return etage * 100 + numero;
}
}
public bool PossedeWifi
{
get
{
return possedeWifi;
}
}
public Local(int etage, bool possedeWifi, int numero)
{
this.etage = etage;
this.possedeWifi = possedeWifi;
Numero = numero;
}
public Local(int etage, int numero) : this(etage, true, numero) { }
public Local(int local, bool possedeWifi) : this(local / 100, possedeWifi, local % 100) { }
public void AjouteActivité(ActivitéInterne a)
{
historiquesActivités.Add(a.Id, a);
}
}
class Réunion : ActivitéInterne
{
private HashSet<Employé<Local>> employésConvoqués;
public Réunion(string label, DateTime début, DateTime fin, Local lieu) : base(label, début, fin, lieu) { }
public Employé<Local> EmployéConvoqués
{
set
{
employésConvoqués.Add(value);
}
}
}
The error message says that "cast is redundant". This is because you have already tested for "activité as Réunion != null". The compiler figures out that in the 'if' clause this condition is already true, therefore the cast is not meaningful. On the other hand you cannot access activité.EmployéConvoqués because the static type of activité is not Réunion.
All you have to do is introduce a new variable when testing the type. Like this:
if (activité is Réunion réunion) {
réunion.EmployéConvoqués = activité;
}
However if you try this you will see that the assignment cannot be done because you are trying to assign an activity to an Employé<Local>. These are not compatible types. Perhaps you meant something like
foreach (Activité<T> activité in activités) {
if (activité is Réunion réunion && this is Employé<Local> employéLocal) {
réunion.EmployéConvoqués = employéLocal;
}
}
Comment: in the definition of Réunion you are adding to HashSet<Employé<Local>> employésConvoqués when setting the property Employé<Local> EmployéConvoqués. From a style point of view this is strange because people generally expect a property of type Employé<Local> will represent a single Employé<Local> rather than a collection of Employé<Local>. I would suggest that you remove the setter and instead define
public void Ajoute( Employé<Local> employéConvoqué) {
this.employésConvoqués.Add(employéConvoqué);
}

What I am doing wrong with below "Set" property?

I was trying to create simple event and below is the block of code but its not working. When I try to debug, as soon as we create Point object it is throwing "StackOverFlowException" at "Set" property(even before we assign the value p.x=10). What I am doing wrong?
using System;
namespace Workshop
{
public class Point
{
public int x
{
get { return x; }
set
{
x = value;
onPointeChanged();
}
}
public int y
{
get { return y; }
set
{
y = value;
onPointeChanged();
}
}
public event EventHandler pointchanged;
private void onPointeChanged()
{
if (pointchanged != null)
pointchanged(this, EventArgs.Empty);
}
}
public class Program
{
public static void Main(String[] args)
{
Point p = new Point();
p.pointchanged += HandleEvent;
p.x = 10;
}
public static void HandleEvent(object obj, EventArgs sender)
{
Console.WriteLine("Event Raised");
}
}
}
Thanks
You are calling the set method indefinitelly until you run out of stack memory. What you're doing with
x = value;
is you're calling the x property's setter, which in turn does x = value, so it calls itself, and so on, and so on for all eternity.
To fix this, introduce a field:
private int x;
public int X
{
get => x;
set
{
x = value;
OnPointChanged();
}
}
This is the proper way of creating properties with custom logic behind get and/or set. If you didn't have your OnPointChanged() logic you could just do
public int X { get; set; }
which would generate the following code for you under the hood:
private int x;
public int X { get => x; set => x = value; }
The problem is you are assigning the property a value in its own setter:
public int x
{
get { return x; }
set
{
x = value; // <-- see you are assigning `value` to your `x` property.
onPointeChanged();
}
}
This will loop over and over again ad infinitum. You need to create a backing field:
private int _myField;
public int BetterNameThanX
{
get { return _myField; }
set
{
_myField = value;
onPointeChanged();
}
}
You have defined properties and you return every own property which causes recursivity on get and set scopes. Try to define private attributes and expose it by properties:
public class Point
{
private int _x;
public int x
{
get { return _x; }
set
{
_x = value;
onPointeChanged();
}
}
private int _y;
public int y
{
get { return _y; }
set
{
_y = value;
onPointeChanged();
}
}
public event EventHandler pointchanged;
private void onPointeChanged()
{
if (pointchanged != null)
pointchanged(this, EventArgs.Empty);
}
}

Creating two C# class definitions with a driver to test classes, but not sure why so many errors?

I am new to C# and was asked to create two class definitions (customer and order) using partial code and with the suggested class names, methods, contructors and following an example. I am not sure why I am getting so many errors when I build/debug?
After this is finished, I need to create another program that builds onto this one. Our instructor also asked us not to use validation...
Some of my most common errors are:
expected: ; (in a place in my code where I believe there should not be a semi-colon and
Error "Expected class, delegate, enum, interface, or struct.
Here is my code:
public class clsOrder
{
//declare class variables
protected string cstrDescription;
protected int cintQuantity;
protected decimal cdecPrice;
protected decimal cdecExtendedPrice;
//shared variables
static decimal cdecTotalPrice;
static int cintTotalCount;
//declare constructors
public clsOrder();
}
public clsOrde r(string strDescription,
int intQuantity, decimal decPrice)
}
//declare property methods
{
this.Description = string strDescription;
this.Quantity = int intQuantity;
this.Price = decimal decPrice;
//declare read-only properties
public decimal ExtendedPrice
}
public string Description
{
get
{
return strDescription;
}
set
{
strDescription = value;
}
}
public int Quantity
{
get
{
return intQuantity;
}
set
{
intQuantity = value;
}
}
public decimal Price
{
get
{
return decPrice;
}
set
{
decPrice = value;
}
}
get
{
return cdecExtendedPrice;
}
}
//declare Shared (static) ReadOnly Properites
public static decimal TotalPrice
{
get
{
return cdecTotalPrice;
}
}
public static int TotalCount
{
get
{
return cintTotalCount;
}
}
//declare supporting methods
public void calcExtendedPrice()
{
cdecExtendedPrice = cintQuantity * cdecPrice;
}
public void accumulateTotals()
{
cdecTotalPrice += cdecExtendedPrice;
cintTotalCount += 1;
}
public static void resetTotals()
{
cdecTotalPrice = 0;
cintTotalCount = 0;
}
}//end of Class
}//end of namespace
And
public class clsCustomer
{
//declare class variables
private string cstrName;
private string cstrStreet;
private string cstrCity;
private string cstrState;
private string cstrZip;
//declare constructors
public class clsCustomer()
}
public clsCustomer(string strName,
string strStreet, string strCity,
string strState, string strZip)
}
//declare property methods
{
this.Name = cstrName;
this.Street = cstrStreet;
this.City = cstrCity;
this.State = cstrState;
this.Zip = cstrZip;
}
public string Name
{
get
{
return cstrName;
}
set
{
cstrName = value;
}
}
public string Street
{
get
{
return cstrStreet;
}
set
{
cstrStreet = value;
}
}
public string City
{
get
{
return cstrCity;
}
set
{
cstrCity = value;
}
}
public string State
{
get
{
return cstrState;
}
set
{
cstrState = value;
}
}
public string Zip
{
get
{
return cstrZip;
}
set
{
cstringZip = value;
}
}
Any help would be very much appreciated, thank you.

Already contains a definition for

I have a class called Assign and
private int SeatNumber;
public Assign(int SeatNum)
{
SeatNumber = SeatNum;
}
public int SeatNumber
{
get { return SeatNumber; }
set { SeatNumber = value; }
}
I have no idea why I am getting the following error
EThe type 'WindowsFormsApplication1.Assign' already contains a definition for 'SeatNumber'
What is wrong?
You're declaring the same variable twice here.
private int SeatNumber;
public int SeatNumber
{
get { return SeatNumber; }
set { SeatNumber = value; }
}
That code defines the same variable twice. If you're using .net 3.0+, you can do auto-implemented properties like this with no private int SeatNumber:
public int SeatNumber
{
get;
set;
}
otherwise, you should do this:
private int SeatNumber_;
public int SeatNumber
{
get { return SeatNumber_; }
set { SeatNumber_ = value; }
}
You should make sure that the variable that backs the property has a different name. It is common to use camelCase for it:
private int seatNumber;
public Assign(int SeatNum)
{
SeatNumber = SeatNum;
}
public int SeatNumber
{
get { return seatNumber; }
set { seatNumber = value; }
}
Moreover, in situations where the getter ans setter are trivial, starting with C# 3.0 you can use automatic properties, like this:
public int SeatNumber {get; set;}
This lets you remove the backing variable: the compiler will take care of it for you.
The private and public variables can't have the same name, that is where the conflict is coming from. Do this:
private int _seatNumber;
public Assign(int SeatNum)
{
SeatNumber = SeatNum;
}
public int SeatNumber
{
get { return _seatNumber; }
set { _seatNumber = value; }
}
The underscore notation is common for private variables.
The error is thrown because you're basically assigning something to SeatNumber in the constructor and then doing it again in the property. When creating class fields in Visual Studio, type 'propfull' and hit the tab key twice. This will auto create the field and property for you.
For what it's worth, this is the generally accepted way to structure classes.
class Assign
{
//Fields
private int _seatNumber;
//Properties
public int SeatNumber
{
get { return _seatNumber; }
set { _seatNumber = value; }
}
//Overloaded Constructors
public Assign(int sn)
{
SeatNumber = sn;
}
public Assign()
{
}
//Methods
public void SomeMethod()
{
//insert code
}
public void SomeOtherMethod()
{
//insert code
}
}//END ASSIGN CLASS

What is the proper way to handle an array of one class in another class?

Here are two simple classes to illustrate my question:
class Widget
{
private int _widgetID;
public int WidgetID
{
get { return _widgetID; }
set { _widgetID = value; }
}
private int _categoryID;
public int CategoryID
{
get { return _categoryID; }
set { _categoryID = value; }
}
private string _widgetName;
public string WidgetName
{
get { return _widgetName; }
set { _widgetName = value; }
}
}
And them the second class:
class WidgetCategory
{
private int _widgetCategoryID;
public int WidgetCategoryID
{
get { return _widgetCategoryID; }
set { _widgetCategoryID = value; }
}
private Widget[] _widgets;
public Widget[] Widgets
{
get { return _widgets; }
set { _widgets = value; }
}
private string _widgetCategoryName;
public string WidgetCategoryName
{
get { return _widgetCategoryName; }
set { _widgetCategoryName = value; }
}
}
How would I handle this situation in the most efficient way?
Also, so you know, I will need to nest other classes the same way below the Widget class.
You should create a read-only property of type System.Collections.ObjectModel.Collection<Widget>.
Collection properties should be read only
Use Collection<T>

Categories

Resources