So I was creating a Monopoly console app to explore some design concepts as well as to try to understand Test-Driven Development better.
That being the case, I created unit tests to make sure that all of my classes can be serialized and deserialized properly (because I'm going to need that later and if they can't be I'd rather know that sooner than later so I can avoid rework; doing so has, in fact, helped me catch several flaws in my initial design).
This property is part of a larger Property class. Owner
is the player that owns the property.
What I'm trying to achieve here is that when a player mortgages a particular property, the property should be marked as "Mortgaged" and the player should receive half of the purchase price in cash. When they unmortgage the property, they pay the money back. There will be a few other checks that I haven't written yet as well; for example, game rules specify that you're not allowed to mortgage a property while it still has houses on it. I also don't yet check to see if the player has enough money to unmortgage the property, but I plan to add that shortly as that's a trivial rule to implement. That's why I'm using a setter here instead of an auto-generated property.
Here's the problem: this serializes and deserializes without throwing an exception, but if I serialize a mortgaged property it'll add the money a second time when I deserialize it (i.e. deserializing basically has the effect of re-mortgaging the property), so needless to say the unit test fails (which it should given that there's an obvious bug). I suppose that that's not surprising given that that's exactly how I wrote it - when you change its value it'll either mortgage or unmortgage the property.
Here's the code:
[JsonProperty(Order = 1)]
public Player Owner
{
get;
set;
}
private bool _isMortaged = false;
[JsonProperty(Order = 2)]
public bool IsMortgaged
{
get { return _isMortaged; }
set
{
if (!IsOwned)
{
throw new InvalidOperationException("You can't mortgage a property that no one owns");
}
// If we're setting this property to the same thing that it
// already was, log it. You could argue that that would indicate
// a bug (it probably would), but throwing an exception here
// breaks deserialization.
Debug.WriteIf(value == _isMortaged, $"Setting IsMortgaged to the same thing as it was before. Stack trace:{Environment.NewLine}{(new StackTrace()).ToString()}");
// If we're setting this to the same thing that it already was,
// then the setter should have no effect at all.
if (value != _isMortaged)
{
// The player is mortgaging the property
if (value)
{
_isMortaged = true;
Owner.Money += (PurchasePrice / 2);
}
// The player is unmortgaging the property
else
{
_isMortaged = false;
Owner.Money -= (PurchasePrice / 2);
}
}
}
}
Is there an easy way to have a different setter for deserialization, or to tell whether or not I'm deserializing in the setter? (The latter seems like a "hack"). I suppose that there's also the possibility of writing a custom deserializer, which would solve the problem I guess, but I'd much rather avoid that if possible (it doesn't seem like a particularly "clean" way of doing this).
Alternatively, is this just a design flaw?