// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections; using System.Collections.Generic; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Http.Internal { /// /// The HttpRequest query string collection /// public class QueryCollection : IQueryCollection { public static readonly QueryCollection Empty = new QueryCollection(); #if NETSTANDARD1_3 private static readonly string[] EmptyKeys = Array.Empty(); private static readonly StringValues[] EmptyValues = Array.Empty(); #else private static readonly string[] EmptyKeys = new string[0]; private static readonly StringValues[] EmptyValues = new StringValues[0]; #endif private static readonly Enumerator EmptyEnumerator = new Enumerator(); // Pre-box private static readonly IEnumerator> EmptyIEnumeratorType = EmptyEnumerator; private static readonly IEnumerator EmptyIEnumerator = EmptyEnumerator; private Dictionary Store { get; set; } public QueryCollection() { } public QueryCollection(Dictionary store) { Store = store; } public QueryCollection(QueryCollection store) { Store = store.Store; } public QueryCollection(int capacity) { Store = new Dictionary(capacity, StringComparer.OrdinalIgnoreCase); } /// /// Get or sets the associated value from the collection as a single string. /// /// The header name. /// the associated value from the collection as a StringValues or StringValues.Empty if the key is not present. public StringValues this[string key] { get { if (Store == null) { return StringValues.Empty; } StringValues value; if (TryGetValue(key, out value)) { return value; } return StringValues.Empty; } } /// /// Gets the number of elements contained in the ;. /// /// The number of elements contained in the . public int Count { get { if (Store == null) { return 0; } return Store.Count; } } public ICollection Keys { get { if (Store == null) { return EmptyKeys; } return Store.Keys; } } /// /// Determines whether the contains a specific key. /// /// The key. /// true if the contains a specific key; otherwise, false. public bool ContainsKey(string key) { if (Store == null) { return false; } return Store.ContainsKey(key); } /// /// Retrieves a value from the dictionary. /// /// The header name. /// The value. /// true if the contains the key; otherwise, false. public bool TryGetValue(string key, out StringValues value) { if (Store == null) { value = default(StringValues); return false; } return Store.TryGetValue(key, out value); } /// /// Returns an enumerator that iterates through a collection. /// /// An object that can be used to iterate through the collection. public Enumerator GetEnumerator() { if (Store == null || Store.Count == 0) { // Non-boxed Enumerator return EmptyEnumerator; } return new Enumerator(Store.GetEnumerator()); } /// /// Returns an enumerator that iterates through a collection. /// /// An object that can be used to iterate through the collection. IEnumerator> IEnumerable>.GetEnumerator() { if (Store == null || Store.Count == 0) { // Non-boxed Enumerator return EmptyIEnumeratorType; } return Store.GetEnumerator(); } /// /// Returns an enumerator that iterates through a collection. /// /// An object that can be used to iterate through the collection. IEnumerator IEnumerable.GetEnumerator() { if (Store == null || Store.Count == 0) { // Non-boxed Enumerator return EmptyIEnumerator; } return Store.GetEnumerator(); } public struct Enumerator : IEnumerator> { // Do NOT make this readonly, or MoveNext will not work private Dictionary.Enumerator _dictionaryEnumerator; private bool _notEmpty; internal Enumerator(Dictionary.Enumerator dictionaryEnumerator) { _dictionaryEnumerator = dictionaryEnumerator; _notEmpty = true; } public bool MoveNext() { if (_notEmpty) { return _dictionaryEnumerator.MoveNext(); } return false; } public KeyValuePair Current { get { if (_notEmpty) { return _dictionaryEnumerator.Current; } return default(KeyValuePair); } } public void Dispose() { } object IEnumerator.Current { get { return Current; } } void IEnumerator.Reset() { if (_notEmpty) { ((IEnumerator)_dictionaryEnumerator).Reset(); } } } } }