向扩展添加方法

Adding methods to extensions

我找到了一些代码来制作固定大小 hereQueue。现在我正在尝试为此添加一个 Average 方法,但我收到消息:

'Queue' does not contain a definition for 'Average' and the best extension method overload 'Queryable.Average(IQueryable)' requires a receiver of type 'IQueryable'

对于正常的 Queue 我可以使用 Average 方法。为什么我不能在这里访问它?

同样先转换为数组或列表再取平均值也不行:queue.ToArray().Average().

最后,为什么最好将此扩展包装在新的 class 中,而不是通过 public class FixedSizeQueue<T> : Queue<T>Queue 继承?

public class FixedSizeQueue<T>
{
    private Queue<T> queue;

    public FixedSizeQueue(int capacity)
    {
        Capacity = capacity;
        queue = new Queue<T>(capacity);
    }

    public int Capacity { get; private set; }

    public int Count { get { return queue.Count; } }

    public T Average()
    {
        return queue.Average();
    }

    public void Clear()
    {
        queue.Clear();
    }

    public T ElementAt(int i)
    {
        return queue.ElementAt(i);
    }

    public T Enqueue(T item)
    {
        queue.Enqueue(item);
        if (queue.Count > Capacity)
        {
            return queue.Dequeue();
        }
        else
        {
            //if you want this to do something else, such as return the `peek` value
            //modify as desired.
            return default(T);
        }
    }

    public T Peek()
    {
        return queue.Peek();
    }

    // Got it from somewhere, don't know where.
    public IEnumerator<T> GetEnumerator()
    {
        return ((IEnumerable<T>)queue).GetEnumerator();
    }

    //IEnumerator IEnumerable.GetEnumerator()
    //{
    //    return ((IEnumerable<T>)queue).GetEnumerator();
    //}
}

Average 仅适用于以下类型:decimalintlongfloatdouble

现在您的 collection 是 T,这是无法平均的。 你需要在你的collection上使用一个选择器,直接写下来。

例如,假设您有以下 class

public class MyData
{
    public string Title {get;set;} = "";
    public double Value {get;set;} = 0d;
}

并假设您的队列为:

FixedSizeQueue<MyData> queue = new FixedSizeQueue<MyData>();
// add some data ...
queue.Enqueue(new MyData());

现在要获得平均值,你需要告诉你想要平均的东西,这里我想要 Value 属性 然后我会这样做(非常明确)

double averageValue = queue.ToList().Average(data => data.Value);

不能使用此方法,因为它是IEnumerable<T>的扩展方法(Average不带参数是IEnumerable<int>IEnumerable<double>等的一组扩展方法)并且您的 FixedSizeQueue 没有实现 IEnumerable<T> 接口。如果您实施它(并将实施委托给 _queue:

public class FixedSizeQueue<T> : IEnumerable<T> {
    private Queue<T> queue;

    public FixedSizeQueue(int capacity) {
        Capacity = capacity;
        queue = new Queue<T>(capacity);
    }

    public int Capacity { get; private set; }

    public int Count
    {
        get { return queue.Count; }
    }

    public void Clear() {
        queue.Clear();
    }

    public T Enqueue(T item) {
        queue.Enqueue(item);
        if (queue.Count > Capacity) {
            return queue.Dequeue();
        }
        else {
            //if you want this to do something else, such as return the `peek` value
            //modify as desired.
            return default(T);
        }
    }

    public T Peek() {
        return queue.Peek();
    }

    public IEnumerator<T> GetEnumerator() {
        return ((IEnumerable<T>) this.queue).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
}

那么您就可以像往常一样使用Average了:

var queue = new FixedSizeQueue<float>(10);
var result = queue.Average();

对于非数字类型的队列,您仍然可以使用 Average 接受参数的重载:

var queue = new FixedSizeQueue<string>(10);
var result = queue.Average(x => x.Length);