2014-04-28 140 views
0

我有两个简单的类。一个叫UseCounter<T>,它是一个简单的容器,用于存放其他对象的简单容器,同时保存一些关于其用法的信息(已经使用了多少次,以及是否可以再次使用)。从集合更新对象Linq'd不会更新集合中的对象

然后是Dispenser<T>,它包含UseConter<T>的集合,用于从集合中获取正确的元素,然后更新其信息。

我遇到的麻烦是在分配器的Get()方法中。它应返回最低组合CountTotalCount的对象,然后调用Increase()方法以增加计数。

但是,当我运行此代码时,Dispenser<T>始终返回相同的元素。这就像Linq'd元素不是对象的引用,而是它的副本,所以Increase()方法只增加本地对象的属性,但不增加集合中的属性。

我在这里失去,因为我从来没有遇到过这样的行为。

这里谈到的代码:

UseCounter:

public class UseCounter<T> 
{ 
    public T Element { get; private set; } 
    public int TotalCount { get; private set; } 
    public int Count { get; private set; } 
    public bool Useful { get; set; } 

    public UseCounter(T element) 
    { 
     this.Element = element; 
     this.Count = 0; 
     this.TotalCount = 0; 
     this.Useful = true; 
    } 

    public void IncreaseCounter() 
    { 
     this.Count++; 
     this.TotalCount++; 
    } 

    public void DecreaseCounter() 
    { 
     if(this.Count == 0) 
     { 
      throw new ArgumentOutOfRangeException("Count cannot be lower than 0!"); 
     } 

     this.Count--; 
    } 
} 

饮水机

private readonly object _elementLocker = new object(); 
    private IEnumerable<UseCounter<T>> _elements; 

    public IEnumerable<T> Elements 
    { 
     get { return _elements.Select(e => e.Element); } 
    } 

    public int FinishedCount 
    { 
     get 
     { 
      lock (_elementLocker) 
      { 
       return _elements.Where(e => e.Useful == false).Count(); 
      } 
     } 
    } 

    public int CurrentlyWorkingCount 
    { 
     get 
     { 
      lock (_elementLocker) 
      { 
       return _elements.Where(e => e.Count > 0).Count(); 
      } 
     } 
    } 

    public Dispenser(IEnumerable<T> elements) 
    { 
     this._elements = elements 
      .Distinct() 
      .Select(e => new UseCounter<T>(e)); 
    } 

    public T Get() 
    { 
     lock(_elementLocker) 
     { 
      var lCount = _elements 
       .Where(e => e.Useful == true) 
       .Select(e => e.Count).Min(); 

      var lTCount = _elements 
       .Where(e => e.Useful == true) 
       .Where(e => e.Count == lCount) 
       .Select(e => e.TotalCount).Min(); 

      var el = _elements 
       .Where(e => e.Useful == true) 
       .First(e => e.Count == lCount && e.TotalCount == lTCount); 

      el.IncreaseCounter(); 

      return el.Element; 
     } 
    } 

    public void Report(T element, bool successful) 
    { 
     lock(_elementLocker) 
     { 
      var el = _elements 
       .First(e => e.Element == element); 
      el.DecreaseCounter(); 

      if(el.Useful == true && successful == true) 
      { 
       el.Useful = false; 
      } 
     } 
    } 

回答

3

这就是问题所在:

this._elements = elements 
    .Distinct() 
    .Select(e => new UseCounter<T>(e)); 

这是懒惰的。每次遍历_elements时,它将返回到原始源数据,找到一个不同的集合,然后将该集合投影到新实例的UseCounter实例序列上。您对这些实例所做的任何更改都与您在下一次迭代_elements时发生的变化无关。

如果你感到幸福的一组输入要素的建设被“冻结”,你可以兑现查询,以便只执行一次:

this._elements = elements 
    .Distinct() 
    .Select(e => new UseCounter<T>(e)) 
    .ToList(); 

现在每次迭代elements时间,你正在迭代相同的引用序列。