| File: System\Dynamic\Utils\ListArgumentProvider.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using LinqError = System.Linq.Expressions.Error; namespace System.Dynamic.Utils { internal abstract class ListProvider<T> : IList<T> where T : class { protected abstract T First { get; } protected abstract int ElementCount { get; } protected abstract T GetElement(int index); #region IList<T> Members public int IndexOf(T item) { if (First == item) { return 0; } for (int i = 1, n = ElementCount; i < n; i++) { if (GetElement(i) == item) { return i; } } return -1; } [ExcludeFromCodeCoverage(Justification = "Unreachable")] public void Insert(int index, T item) { throw ContractUtils.Unreachable; } [ExcludeFromCodeCoverage(Justification = "Unreachable")] public void RemoveAt(int index) { throw ContractUtils.Unreachable; } public T this[int index] { get { if (index == 0) { return First; } return GetElement(index); } [ExcludeFromCodeCoverage(Justification = "Unreachable")] set { throw ContractUtils.Unreachable; } } #endregion #region ICollection<T> Members [ExcludeFromCodeCoverage(Justification = "Unreachable")] public void Add(T item) { throw ContractUtils.Unreachable; } [ExcludeFromCodeCoverage(Justification = "Unreachable")] public void Clear() { throw ContractUtils.Unreachable; } public bool Contains(T item) => IndexOf(item) != -1; public void CopyTo(T[] array, int index) { ArgumentNullException.ThrowIfNull(array); if (index < 0) { throw LinqError.ArgumentOutOfRange(nameof(index)); } int n = ElementCount; Debug.Assert(n > 0); if (index + n > array.Length) { throw new ArgumentException(); } array[index++] = First; for (int i = 1; i < n; i++) { array[index++] = GetElement(i); } } public int Count => ElementCount; [ExcludeFromCodeCoverage(Justification = "Unreachable")] public bool IsReadOnly => true; [ExcludeFromCodeCoverage(Justification = "Unreachable")] public bool Remove(T item) { throw ContractUtils.Unreachable; } #endregion #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator() { yield return First; for (int i = 1, n = ElementCount; i < n; i++) { yield return GetElement(i); } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #endregion } /// <summary> /// Provides a wrapper around an IArgumentProvider which exposes the argument providers /// members out as an IList of Expression. This is used to avoid allocating an array /// which needs to be stored inside of a ReadOnlyCollection. Instead this type has /// the same amount of overhead as an array without duplicating the storage of the /// elements. This ensures that internally we can avoid creating and copying arrays /// while users of the Expression trees also don't pay a size penalty for this internal /// optimization. See IArgumentProvider for more general information on the Expression /// tree optimizations being used here. /// </summary> internal sealed class ListArgumentProvider : ListProvider<Expression> { private readonly IArgumentProvider _provider; private readonly Expression _arg0; internal ListArgumentProvider(IArgumentProvider provider, Expression arg0) { _provider = provider; _arg0 = arg0; } protected override Expression First => _arg0; protected override int ElementCount => _provider.ArgumentCount; protected override Expression GetElement(int index) => _provider.GetArgument(index); } }