diff --git a/Core/Collections/VirtualList.cs b/Core/Collections/VirtualList.cs
new file mode 100644
index 00000000..4db3de9f
--- /dev/null
+++ b/Core/Collections/VirtualList.cs
@@ -0,0 +1,234 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Vanara.Collections;
+
+/// Interface that defines the methods for a virtual list. This interface is used by the class.
+/// The type of the element.
+///
+public interface IVirtualListMethods : IVirtualReadOnlyListMethods
+{
+ /// Adds an item to the end of the list.
+ /// The object to add to the list.
+ void AddItem(T item);
+
+ /// Inserts an item to the list at the specified index.
+ /// The zero-based index at which item should be inserted.
+ /// The object to insert into the list.
+ void InsertItemAt(int index, T item);
+
+ /// Removes the item at the specified index.
+ /// The zero-based index of the item to remove.
+ void RemoveItemAt(int index);
+
+ /// Sets the element at the specified index.
+ /// The zero-based index of the element to set.
+ /// The element at the specified index.
+ void SetItemAt(int index, T value);
+}
+
+///
+/// Interface that defines the methods for a virtual read-only list. This interface is used by the class.
+///
+/// The type of the element.
+public interface IVirtualReadOnlyListMethods
+{
+ /// Gets the number of elements in the collection.
+ /// The number of elements in the collection.
+ int GetItemCount();
+
+ /// Tries to get the element at the specified index.
+ /// The zero-based index of the element to get.
+ /// The value, if is a valid index; or if not.
+ /// if the list contains an element at the specified index; otherwise, .
+ bool TryGet(int index, [NotNullWhen(true)] out T? value);
+}
+
+/// A virtual list that implements a lot of the scaffolding.
+/// The element type.
+public class VirtualList : VirtualReadOnlyList, IList
+{
+ /// The implementation.
+ protected readonly IVirtualListMethods impl;
+
+ /// Initializes a new instance of the class.
+ public VirtualList(IVirtualListMethods impl) : base(impl) => this.impl = impl;
+
+ ///
+ bool ICollection.IsReadOnly => false;
+
+ ///
+ public new T this[int index]
+ {
+ get => base[index];
+ set => impl.SetItemAt(index, value);
+ }
+
+ ///
+ public void Add(T item) => impl.AddItem(item);
+
+ ///
+ public void Clear()
+ {
+ for (int i = Count - 1; i >= 0; i--)
+ RemoveAt(i);
+ }
+
+ ///
+ public void Insert(int index, T item) => impl.InsertItemAt(index, item);
+
+ ///
+ public bool Remove(T item)
+ {
+ int i = IndexOf(item);
+ if (i >= 0)
+ {
+ RemoveAt(i);
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ public void RemoveAt(int index) => impl.RemoveItemAt(index);
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+}
+
+/// Wrapper for that allows for the use of delegates instead of implementing the interface.
+/// The element type.
+///
+public class VirtualListMethodCarrier : IVirtualListMethods
+{
+ /// Initializes a new instance of the class.
+ /// Delegate that tries to get the element at the specified index.
+ /// Delegate that gets the number of elements in the collection.
+ /// Delegate that adds an item to the end of the list.
+ /// Delegate that inserts an item to the list at the specified index.
+ /// Delegate that removes the item at the specified index.
+ /// Delegate that sets the element at the specified index.
+ public VirtualListMethodCarrier(VirtualReadOnlyList.TryGetDelegate tryGet, Func getCount, Action? add = null, Action? insert = null, Action? removeAt = null, Action? setAt = null)
+ {
+ TryGet = tryGet;
+ GetCount = getCount;
+ Add = add;
+ Insert = insert;
+ RemoveAt = removeAt;
+ SetAt = setAt;
+ }
+
+ /// Delegate that adds an item to the end of the list.
+ public Action? Add { get; }
+
+ /// Delegate that gets the number of elements in the collection.
+ public Func GetCount { get; }
+
+ /// Delegate that inserts an item to the list at the specified index.
+ public Action? Insert { get; }
+
+ /// Delegate that removes the item at the specified index.
+ public Action? RemoveAt { get; }
+
+ /// Delegate that sets the element at the specified index.
+ public Action? SetAt { get; }
+
+ /// Delegate that tries to get the element at the specified index.
+ public VirtualReadOnlyList.TryGetDelegate TryGet { get; }
+
+ ///
+ void IVirtualListMethods.AddItem(T item) => Add?.Invoke(item);
+
+ ///
+ int IVirtualReadOnlyListMethods.GetItemCount() => GetCount();
+
+ ///
+ void IVirtualListMethods.InsertItemAt(int index, T item) => Insert?.Invoke(index, item);
+
+ ///
+ void IVirtualListMethods.RemoveItemAt(int index) => RemoveAt?.Invoke(index);
+
+ ///
+ void IVirtualListMethods.SetItemAt(int index, T value) => SetAt?.Invoke(index, value);
+
+ ///
+ bool IVirtualReadOnlyListMethods.TryGet(int index, [NotNullWhen(true)] out T? value) => TryGet(index, out value);
+}
+
+/// A virtual read-only list that implements a lot of the scaffolding.
+/// The element type.
+public class VirtualReadOnlyList : IReadOnlyList
+{
+ /// The read only implementation.
+ protected readonly IVirtualReadOnlyListMethods readOnlyImpl;
+
+ /// Initializes a new instance of the class.
+ public VirtualReadOnlyList(IVirtualReadOnlyListMethods impl) => readOnlyImpl = impl;
+
+ /// Delegate for a method that tries to get the element at the specified index.
+ /// The zero-based index of the element to get.
+ /// The value, if is a valid index; or if not.
+ /// if the list contains an element at the specified index; otherwise, .
+ public delegate bool TryGetDelegate(int index, [NotNullWhen(true)] out T? value);
+
+ ///
+ public virtual int Count => readOnlyImpl.GetItemCount();
+
+ ///
+ public virtual T this[int index] => readOnlyImpl.TryGet(index, out T? v) ? v : throw new ArgumentOutOfRangeException(nameof(index));
+
+ ///
+ public virtual bool Contains(T item) => IndexOf(item) >= 0;
+
+ ///
+ public virtual void CopyTo(T[] array, int arrayIndex)
+ {
+ if (array is null)
+ throw new ArgumentNullException(nameof(array));
+ if (arrayIndex < 0 || arrayIndex > array.Length)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex));
+ if (array.Length - arrayIndex < Count)
+ throw new ArgumentException("The number of elements in the source ICollection is greater than the available space from arrayIndex to the end of the destination array.");
+
+ for (int i = 0; i < Count; i++)
+ array[arrayIndex + i] = this[i];
+ }
+
+ ///
+ public virtual IEnumerator GetEnumerator()
+ {
+ for (int i = 0; i < Count; i++)
+ yield return this[i];
+ }
+
+ ///
+ public virtual int IndexOf(T item)
+ {
+ for (int i = 0; i < Count; i++)
+ {
+ /* Unmerged change from project 'Vanara.PInvoke.Printing (net48)'
+ Before:
+ if (Equals(this[i], item))
+ After:
+ {
+ if (Equals(this[i], item))
+ */
+ if (Equals(this[i], item))
+ return i;
+ }
+
+ /* Unmerged change from project 'Vanara.PInvoke.Printing (net48)'
+ Before:
+ return -1;
+ After:
+ }
+
+ return -1;
+ */
+ return -1;
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+}
\ No newline at end of file