从集合中更新对象Linq&#d; dd不会更新集合中的对象

时间:2014-04-28 16:55:02

标签: c# linq

我有两个简单的课程。一个被称为UseCounter<T>并且是其他对象的简单容器,同时保存有关其使用的一些信息(已经使用了多少次以及它是否可以再次重复使用)。

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

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

但是,当我运行此代码时,Dispenser<T>始终返回相同的元素。它就像Linq的元素不是对象的引用,而是它的副本,因此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;
            }
        }
    }

1 个答案:

答案 0 :(得分: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时,你都会迭代相同的引用序列。