EJo*_*ica 1 .net c# json json.net deserialization
所以我创建了一个Monopoly控制台应用程序来探索一些设计概念,以及尝试更好地理解测试驱动开发.
在这种情况下,我创建了单元测试,以确保我的所有类都可以正确地序列化和反序列化(因为我将来需要它,如果他们不能,我宁愿早点知道,所以我可以避免返工;事实上,这样做有助于我在初始设计中遇到一些缺陷.
此属性是较大的Property类的一部分.Owner是拥有该物业的玩家.
我在这里想要实现的是,当一个玩家抵押某个特定的房产时,该房产应该被标记为"抵押",玩家应该以现金收取购买价格的一半.当他们不归还财产时,他们会还钱.还有一些我还没有写过的其他检查; 例如,游戏规则规定,如果房产仍有房屋,则不允许抵押房产.我还没有检查玩家是否有足够的资金来取消房产的抵押,但我计划尽快补充,因为这是一个微不足道的规则来实施.这就是为什么我在这里使用setter而不是自动生成的属性.
这是问题所在:这序列化和反序列化而不抛出异常,但是如果我序列化抵押财产,它会在我反序列化时再添加钱(即反序列化基本上具有重新抵押财产的效果),所以不必要说单元测试失败(它应该给出一个明显的错误).我认为这并不奇怪,因为这正是我写它的方式 - 当你改变它的价值时,它要么抵押要么不归还财产.
这是代码:
[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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
是否有一种简单的方法可以使用不同的setter进行反序列化,或者判断我是否在setter中进行反序列化?(后者似乎是"黑客").我想也有可能编写一个自定义反序列化器,它可以解决我想的问题,但我宁愿避免这种情况(如果可能的话)(这似乎不是一种特别"干净"的方式).
或者,这只是一个设计缺陷吗?
这是一个设计缺陷; setters不应该有明显的更新值(以及那些预期的那些INotifyPropertyChanged)的副作用.
如果你需要特殊的行为,那么要么引入一种特殊的设置方法,要么反过来考虑它:
您正在抵押/取消抵押房产,因此您希望该房产的余额的所有者进行更新
而不是让财产更新所有者的余额(它不应该关注:分离关注 ;您可以改为拥有所有者的余额属性:
public class Property {
public bool IsMortgaged {get;set;}
}
public class Player
{
private List<Property> _properties = new List<Property>();
private double _cash = 0;
public int AvailableMoney =>
_cash + _properties.Where(p => p.IsMortgaged).Select(p => p.MortgageValue).Sum();
}
Run Code Online (Sandbox Code Playgroud)
现在,显然需要更新以正确匹配您的模型,但理想情况下您希望您的数据尽可能愚蠢 ; 财产是否抵押是一个简单的真/假.这是特殊的平衡,没有理由不重新计算它.