Repository: dotnet/runtime
File: src/libraries/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs (C#)

Code before:
        public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, IEnumerable<TDerived> items, IEqualityComparer<TBase>? comparer = null) where TDerived : TBase
        {
            Requires.NotNull(items, nameof(items));

            int i = 0;
            if (items.TryGetCount(out var count))
            {
                if (immutableArray.Length != count)
                {
                    return false;
                }

                if (items is IList<TDerived> itemList)
                {
                    comparer ??= EqualityComparer<TBase>.Default;

                    for (i = 0; i < count; i++)
                    {
                        if (!comparer.Equals(immutableArray[i], itemList[i]))
                        {
                            return false;
                        }
                    }

                    return true;
                }
            }

            comparer ??= EqualityComparer<TBase>.Default;

            int n = immutableArray.Length;
            foreach (TDerived item in items)
            {
                if (i == n)
                {
                    return false;
                }

                if (!comparer.Equals(immutableArray[i], item))
                {
                    return false;
                }

                i++;
            }

            return i == n;
        }

        /// <summary>
        /// Determines whether two sequences are equal according to an equality comparer.

Review comment (refactor):
I think the JIT should be able to de-abstract the foreach loop below instead of us doing it here. How much perf benefit is there with/without this?

Code after:
        public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, IEnumerable<TDerived> items, IEqualityComparer<TBase>? comparer = null) where TDerived : TBase
        {
            if (items is ICollection<TBase> itemsCol)
            {
                immutableArray.ThrowNullRefIfNotInitialized();
                return Enumerable.SequenceEqual(immutableArray.array, itemsCol, comparer);
            }

            return Enumerate(immutableArray, items, comparer);

            static bool Enumerate(ImmutableArray<TBase> immutableArray, IEnumerable<TDerived> items, IEqualityComparer<TBase>? comparer)
            {
                Requires.NotNull(items, nameof(items));

                comparer ??= EqualityComparer<TBase>.Default;

                int i = 0;
                int n = immutableArray.Length;
                foreach (TDerived item in items)
                {
                    if (i == n)
                    {
                        return false;
                    }

                    if (!comparer.Equals(immutableArray[i], item))
                    {
                        return false;
                    }

                    i++;
                }

                return i == n;
            }
        }

        /// <summary>
        /// Determines whether two sequences are equal according to an equality comparer.
        /// </summary>
        /// <typeparam name="TDerived">The type of element in the compared array.</typeparam>
        /// <typeparam name="TBase">The type of element contained by the collection.</typeparam>
        public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, ImmutableArray<TDerived> items, Func<TBase, TBase, bool> predicate) where TDerived : TBase
        {
            Requires.NotNull(predicate, nameof(predicate));
            immutableArray.ThrowNullRefIfNotInitialized();
            items.ThrowNullRefIfNotInitialized();

            if (object.ReferenceEquals(immutableArray.array, items.array))
            {
                return true;