我有一个名为Estimate的类,它有以下字段和属性:
private IList<RouteInformation> _routeMatrix;
public virtual IList<RouteInformation> RouteMatrix
{
get
{
if (_routeMatrix != null && _routeMatrix.Count > 0)
{
var routeMatrix = _routeMatrix.ToList();
routeMatrix =
routeMatrix.OrderBy(tm => tm.Level.LevelType).ThenBy(tm => tm.Level.LevelValue).ToList();
return routeMatrix;
}
else return _routeMatrix;
}
set { _routeMatrix = value; }
}
因此,在getter方法中,我只是按级别类型排序_routeMatrix,然后按级别值排序并返回排序列表。
在我的一个程序中,我有以下代码:
public void SaveApprovers(string[] approvers)
{
int i = 1;
foreach (var approver in approvers)
{
var role = Repository.Get<Role>(long.Parse(approver));
var level = new Models.Level
{
LevelType = LevelType.Approver,
LevelValue = (LevelValue)i,
Role = role
};
Repository.Save(level);
var routeInformation = new Models.RouteInformation
{
Level = level,
RouteObjectType = RouteObjectType.Estimate,
RouteObjectId = _estimate.Id
};
Repository.Save(routeInformation);
_estimate.RouteMatrix.Add(routeInformation); // <--- The problem is here
Repository.Save(_estimate);
i++;
}
}
问题在于,如果有多个批准者(即:approvers
数组的长度大于1,则只会在routeInformation
中添加第一个RouteMatrix
。不知道其他人发生了什么,但Add方法没有给出任何错误。
早些时候,RouteMatrix是一个公共领域。在我将其设为私有并将其封装在公共属性中之后,这个问题就开始出现了。
答案 0 :(得分:2)
当您应用ToList()
时,会创建一个全新的列表,该列表与原始_routeMatrix
列表无关。好吧,它们共享相同的元素,但是当你从一个列表中添加或删除元素时,它不会影响第二个列表。
来自MSDN:
您可以将此方法附加到查询中以获取缓存 查询结果的副本。
因此,您已缓存了您正在成功修改的_routeMatrix
的复制。
要解决此问题,您可以返回 IEnumerable 而不是 IList (禁用估算类之外的集合修改),并为估算类创建AddRouteInformation
方法这会将路线信息添加到_routeMatrix
。使用该方法添加新项目:
_estimate.AddRouteInformation(routeInformation);
Repository.Save(_estimate);
答案 1 :(得分:2)
您的get
成员返回不同的列表,您将添加到该临时列表中。
get
{
if (_routeMatrix != null && _routeMatrix.Count > 0)
{
var routeMatrix = _routeMatrix.ToList(); // ToList creates a _copy_ of the list
...
return routeMatrix;
}
else return _routeMatrix;
}
.....
_estimate.RouteMatrix.Add(routeInformation); // add to the result of ToList()
我认为这里的道德观点并不是让吸气剂过于复杂。当您只想添加()时,排序是浪费精力。
此外,_routeMatrix == null
时会发生不好的事情。这可能不会发生,但if (_routeMatrix != null && ...)
部分会产生误导性噪音。
答案 2 :(得分:1)
问题是你实际上并没有修改_routeMatrix
,而是修改了它的副本。不要在ToList
上发出_routeMatrix
,只需对其进行排序即可。将get
更改为此:
get
{
if (_routeMatrix != null && _routeMatrix.Count > 0)
{
_routeMatrix =
_routeMatrix.OrderBy(tm => tm.Level.LevelType).ThenBy(tm => tm.Level.LevelValue).ToList();
return _routeMatrix;
}
else return _routeMatrix;
}