I am getting into infinite loop in property setter - c#

public int Position
{
get
{
if (Session["Position"] != null)
{
Position = Convert.ToInt32(Session["Position"]);
}
else
{
Position = 5;
}
return Position;
}
set
{
Position = value;
}
}
my program calls the get and goes into if loop and then runs infitely into set code

The error is because in your set {} you are invoking the same setter recursively.
Correct code would be
private int _position;
public int Position
{
get
{
if (Session["Position"] != null)
{
this._position = Convert.ToInt32(Session["Position"]);
}
else
{
this._position = 5;
}
return this._position;
}
set
{
this._position = value;
}
}

Use a member variable or perhaps store it in the session.
private int _position;
public int Position
{
get
{
if (Session["Position"] != null)
{
_position= Convert.ToInt32(Session["Position"]);
}
else
{
_position= 5;
}
return _position;
}
set
{
_position = value;
}
}

There's nothing particularly string-like about session state items.
Why wouldn't you just follow the KISS principle and do something like
public int Position
{
get { return (int) ( Session["Position"] ?? 5 ) ; }
set { Session["Position"] = value ; }
}
or (depending on your actual requirements/specs:
public int Position
{
get { return Session["Pointer"] as int? ?? position ?? 5 ; }
set { position = value ; }
}
private int? position ; // backing store

An auto-implemented property property consists of a getter, a setter and a backing field. If you write the code yourself, a field might not be necessary.
Your getter invokes setter, and the setter invokes setter; that would be infinite recursion. You might need a field for storing Position.
However, if we change it with storing to a field, and the setter in fact doesn't effect. So, the code could be changed to:
public int Position {
set {
}
get {
int x;
return (x=Convert.ToInt32(Session["Position"]))>0?x:5;
}
}
You don't need to check for null, Convert.ToInt32(null) is zero.

Related

C# Calculate total price with datetime and price with live update in wpf

I have a wpf application in C# which is used to book houses.
I want to calculate the total price of a reservation. I have 2 datetimes: Check in & Check Out.
The calculation I need to use = (CheckOut - CheckIn).TotalDays * BnB.Price
BnB.Price is the price per night.
I want the totalprice to update live in the guest View.
So whenever I change the check in and out dates the total price automatically changes.
This is my Reservation Model:
private double _totalprice { get; set; }
private DateTime _checkIn { get; set; }
private DateTime _checkOut { get; set; }
public double TotalPrice
{ get => _totalprice; set { _totalprice = value; Notify("TotalPrice"); } }
public DateTime CheckIn
{ get => _checkIn; set { if (value < _checkOut) { _checkIn = value; }; Notify("CheckIn"); } }
public DateTime CheckOut
{ get => _checkOut; set { if (value > _checkIn) { _checkOut = value; }; Notify("CheckOut"); } }
If I missed something please let me know!
Based on the comments in your question, BnB is a member of the reservation model. Given that, you can change TotalPrice to a readonly property, a property without a set method, and just caluclate the total in the get method. Then, in the setters for CheckIn and CheckOut, call Notify("TotalPrice") to update the UI. You also need to call Notify("TotalPrice") in the setter for BnB, since that member participates in the calculation of TotalPrice.
This assumes that the Reservation Model implements INotifyPropertyChanged and that Notify invokes the PropertyChanged event.
public class Reservation : INotifyPropertyChanged
{
private BnB? _bnb;
private DateTime _checkIn;
private DateTime _checkOut;
public double TotalPrice
{
// Instead of using a field, just calculate TotalPrice on the fly.
get
{
// Check for nulls - since _bnb is the only thing that is
// is nullable in the calculation, it is the only thing we
// need to check.
if (BnB== null)
{
return 0;
}
return (CheckOut - CheckIn).TotalDays * BnB.Price;
}
}
public BnB BnB
{
get => _bnb;
set
{
if (_bnb != value)
{
_bnb = value;
Notify(nameof(BnB));
Notify(nameof(TotalPrice));
}
}
}
public DateTime CheckIn
{
get => _checkIn;
set
{
if (value != _checkIn && value < _checkOut)
{
// I've changed the check to ensure that the new value isn't the
// same as the current value. No sense running this code if nothing
// has actually changed.
_checkIn = value;
}
// Without knowing what Notify does exactly, I can't say for sure. But
// if it is only invoking the PropertyChanged event then these two lines
// should probably be placed inside the if statement. There isn't any
// point to notifying the UI that a change happened if a change didn't
// actually happen.
Notify(nameof(CheckIn));
// You can notify the UI to update TotalPrice within a setter for a
// different property.
Notify(nameof(TotalPrice));
}
}
public DateTime CheckOut
{
get => _checkOut;
set
{
if (value != _checkOut&& value > _checkIn)
{
_checkOut = value;
}
// These might make more sense inside the if statement as well.
Notify(nameof(CheckOut));
Notify(nameof(TotalPrice));
}
}
// Other members of the Reservation model.
}
If you really need to have TotalPrice be a property with a getter / setter and a backing field, then just set the TotalPrice property when you set CheckIn, CheckOut, or BnB.
public class Reservation
{
private BnB? _bnb;
private DateTime _checkIn;
private DateTime _checkOut;
private double _totalPrice;
public double TotalPrice
{
get => _totalPrice;
set
{
if (_totalPrice != value)
{
_totalPrice = value;
Notify("TotalPrice");
}
}
}
public BnB BnB
{
get => _bnb;
set
{
if (_bnb != value)
{
_bnb = value;
Notify(nameof(BnB));
TotalPrice = CalculateTotalPrice();
}
}
}
public DateTime CheckIn
{
get => _checkIn;
set
{
if (value != _checkIn && value < _checkOut)
{
// I've changed the check to ensure that the new value isn't the
// same as the current value. No sense running this code if nothing
// has actually changed.
_checkIn = value;
}
// Without knowing what Notify does exactly, I can't say for sure. But
// if it is only invoking the PropertyChanged event then these two lines
// should probably be placed inside the if statement. There isn't any
// point to notifying the UI that a change happened if a change didn't
// actually happen.
Notify(nameof(CheckIn));
// You can notify the UI to update TotalPrice within a setter for a
// different property.
TotalPrice = CalculateTotalPrice();
}
}
public DateTime CheckOut
{
get => _checkOut;
set
{
if (value != _checkOut&& value > _checkIn)
{
_checkOut = value;
}
// These might make more sense inside the if statement as well.
Notify(nameof(CheckOut));
TotalPrice = CalculateTotalPrice();
}
}
private double CalculateTotalPrice()
{
if (BnB== null)
{
return 0;
}
return (CheckOut - CheckIn).TotalDays * BnB.Price;
}
// Other members of the Reservation model.
}
Also, on a side note you might want to consider switching from double to decimal to represent currency.

My IF property is being ignored in my class when i use it

public class Irritante : Child
{
/*Fields*/
private int ir_numeroBirras;
private double ir_mediaBirras;
/*Properties*/
public int NumeroBirras
{
get { return ir_numeroBirras; }
set { if (value > 0) ir_numeroBirras = value; }
}
public double MediaBirras
{
get { return ir_mediaBirras; }
set { ir_mediaBirras = value; }
}
//Constructor
public Irritante(string nome, int idade, int numBirras, double mediaDasBirras) : base(nome, idade)
{
NumeroBirras = numBirras;
ir_mediaBirras = mediaDasBirras;
}
When i try to use the contructor Irritante with the property NumeroBirras it is ignoring the if(value>0)
This means i can still add a 0 to this field with client code, which i should not be able to, any tips? i cant find it anywhere
The default value of ir_numeroBirras is 0. You can't put a 0 using the property. But if you test using a 0 as parameter value, you are being fooled by the default value.
If you're talking about you shouldn't put a 0 in the parameter of Irritante ctor, that's quite different
public Irritante(string name, int idade, int numBirras, double mediaDasBirras) : base(nome, idade)
{
if(numBirras < 1) throw new ArgumentOutOfRangeException(nameof(numBirras), "Hey, you can't drink 0 beers");
ir_numeroBirras = numBirras;
ir_mediaBirras = mediaDasBirras;
}

Processing multiple values in each other's get property

I am getting a StackOverflow exception on "return TimeOne".
The Timecheck method sets both values depending on their value at any given time. Is there a way to process both values at the outset based on each other?
class Name
{
private string _Timeone
public string TimeOne
{
get
{
return _Timeone
}
set
{
TimeCheck();
_Timeone = value;
}
}
private string _TimeTwo
public string TimeTwo
{
get
{
return _TimeTwo
}
set
{
TimeCheck();
_TimeTwo= value;
}
}
private void TimeCheck()
{
string WrongTime = "....";
if (TimeOne == WrongTime && TimeTwo == WrongTime )
TimeOne = TimeTwo = DateTime.Now.ToString();
else if (TimeOne == WrongTime) TimeOne = TimeTwo
else if TimeTwo == WrongTime) TimeTwo = TimeOne;
}
}
}
The issue is caused by your setters calling TimeCheck, which in turn calls the setters, which calls TimeCheck, ad nauseum.
Break that cycle.
Your TimeCheck function can be rewritten so it sets the backing fields instead of calling the setters:
private void TimeCheck()
{
string WrongTime = "....";
if (_TimeOne == WrongTime && _TimeTwo == WrongTime )
{
_TimeOne = _TimeTwo = DateTime.Now.ToString();
}
else if (_TimeOne == WrongTime)
{
_TimeOne = _TimeTwo;
}
else if (_TimeTwo == WrongTime)
{
_TimeTwo = _TimeOne;
}
}
This breaks the cycle. Your setter can now call TimeCheck without fear of being called back in an endless cycle.
You're getting a stack overflow exception because your setters are calling themselves recursively with no end condition, when you do TimeTwo = value; Instead, you can create a private backing property for each public property and use those in the getters and setters:
private string _timeOne;
private string _timeTwo;
public string TimeOne
{
get { return _timeOne; }
set
{
TimeCheck();
_timeOne = value;
}
}
public string TimeTwo
{
get { return _timeTwo; }
set
{
TimeCheck();
_timeTwo = value;
}
With your current implementation, each time you say TimeOne = value; the setter is being called again, which calls it again, and so on.
EDIT
I agree that TimeCheck() should not be called in the setters. Instead, I think it would be more appropriate to validate those values, and reset them if necessary, elsewhere. Maybe in a service of some sort, or whatever code is setting those properties to begin with.

How to roll back to original value iPropertyChanged? C#

I have a datagrid in my xamarin form app and it got a editable column. The values in the column are from MySql database and user can change the value and store to db. I used IPropertyChanged interface to allow user make the changes to the value. There is one condition when editing the value. The new value must be equal or bigger than the original value. My problem is whenever I enter a value bigger than the original, I cannot edit the value again to previous value. For example, the original value is 10. The new value I enter is 30. If I want to change the value again and this time I set it to 20, it is not allowing me because now the original value is 30 not 10 and 20 is less than 30. How can I retain the original value and compare with it?
public int ActualReading
{
get
{
return _ActualReading;
}
set
{
if (value >= _ActualReading)
{
_ActualReading = value;
RaisePropertyChanged("ActualReading");
}
else
{
UserDialogs.Instance.Alert("Meter readings should not be smaller than previous value.","Error","Ok");
}
}
}
private void RaisePropertyChanged(String Name)
{
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(Name));
}
You have to store the original value. I'm using the following pattern.
Assuming you have a model like this
public class Model
{
public int ActualReading {get; set;}
}
and a viewmodel like this (I removed the INotifyPropertyChanged part for better reading)
public class ViewModel
{
private readonly Model MyModel;
private int _actualReading;
public int ActualReading
{
get { return _actualReading; }
set { _actualReading = value; }
}
public ViewModel(Model model)
{
MyModel = model;
ActualReading = model.ActualReading;
}
public Model GetModel()
{
MyModel.ActualReading = ActualReading;
return MyModel;
}
}
When you create the ViewModel instances you initialize it with the coresponding Model instance. When you have implemented this you can add your check in an easy way like this.
private int _actualReading;
public int ActualReading
{
get { return _actualReading; }
set
{
if (value >= MyModel.ActualReading)
{
_actualReading = value;
}
else
{
UserDialogs.Instance.Alert("Meter readings should not be smaller than previous value.", "Error", "Ok");
}
}
}

Can't figure out why Object reference is null

Working on a program for class, and am about 95% complete, but have run into a roadblock. I've got a Flight class that holds information about the flight, as well as a seating chart. Using a windows form listbox to select from the flight objects I created by reading from a text file. I can get values for every property from the class object, except for one, SeatChart.
Here's the pertinent code in the main program:
private void lstFlights_SelectedIndexChanged(object sender, EventArgs e)
{
curFlight = (Flight)lstFlights.SelectedItem;
DisplayNewFlightChart();
}
private void DisplayNewFlightChart()
{
int seats = curFlight.Rows * curFlight.Seats;
lstSeatingChart.Items.Clear();
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
}
And here is the code from the class:
class Flight
{
private string mPlane;
private string mDepartureTime;
private string mDestination;
private int mRows;
private int mSeats;
private string[] mSeatChart;
public Flight()
{
}
// Create the overloaded Constructor
public Flight(string planeType, string departureTime,
string destination, int numRows,
int numSeatsPerRow)
{
this.Plane = planeType;
this.DepartureTime = departureTime;
this.Destination = destination;
this.Rows = numRows;
this.Seats = numSeatsPerRow;
this.SeatChart = mSeatChart;
mSeatChart = new string[Rows * Seats];
for (int seat = 0; seat <= mSeatChart.GetUpperBound(0); seat++)
{
mSeatChart[seat] = "Open";
}
}
public string Plane
{
get { return mPlane; }
set { mPlane = value; }
}
public string DepartureTime
{
get { return mDepartureTime; }
set { mDepartureTime = value; }
}
public string Destination
{
get { return mDestination; }
set { mDestination = value; }
}
public int Rows
{
get { return mRows; }
set { mRows = value; }
}
public int Seats
{
get { return mSeats; }
set { mSeats = value; }
}
public string[] SeatChart
{
get { return mSeatChart; }
set { mSeatChart = value; }
}
public void MakeReservation(string passName, int seat)
{
bool seatTaken = false;
if (mSeatChart[seat] != "Open") seatTaken = true;
if (passName != "" && seatTaken == false)
{
mSeatChart[seat] = passName;
}
else
{
MessageBox.Show("Please Enter a Passenger Name, in an unreserved seat");
}
}
It's telling me the curFlight.SeatChart is null, even though I can pull .Rows and .Seats from the curFlight just fine. I have no clue why .SeatChart is messing up. lstFlights is the list of flight objects pulled from the text file, and lstSeatingChart is where I want to display a list of seats.
You are setting SeatChart to mSeatChart, which is null at that time. So no reference to an object is made for this.SeatChart.
After that you initialize mSeatChart and fill it.
You should move setting this.SeatChart after initializing mSeatChart.
mSeatChart = new string[Rows * Seats];
this.SeatChart = mSeatChart;
Edit:
In addition, SeatChart is the property and mSeatChart is the member variable. SeatChart will be used to expose mSeatChart, so it's really weird to set SeatChart with mSeatChart. So weird that I didn't even think you were doing that.
So in your case leave the following out in the constructor:
this.SeatChart = mSeatChart;
I think the actual cause of your issue is somewhere else in the code, where you initiate Flight and fill the list. If I understand correctly you get a null reference error on the concatenation in the for loop?
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
Check where you initate each Flight object. I bet you are using the empty constructor: new Flight()
Remove the empty constructor, because you don't expect empty values apparently. And if you really need the empty constructor then either initiate all member variables as expected or perform a null check wherever you want to use them.
And once you found the cause, make sure you change the for loop to
for (int x = 0; x < seats; x++)
since you are checking for the number of seats and do a zero-based loop. If x = seats you would have performed the loop seats + 1 times (rows*seats + 1).
If your code relies on a particular property never being null, you need to make sure it is initialized in all constructors.
Based on the logic of your class, I would suggest you shouldn't have a parameter less constructor. It doesn't make sense to have a flight that didn't have a known number of seats (in your implementation at least).
Also some style things.
You don't need to declare your private instance variables. Just use
public string destination {get; set;}
Declare "open" as a class constant and use that constant rather than the hard coded string value.

Categories