diff --git a/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt b/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt index e5c33308aec..ef20cd29aba 100644 --- a/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt +++ b/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt @@ -93,7 +93,6 @@ namespace Akka.Actor public System.Collections.Generic.IEnumerable GetChildren() { } public static Akka.Actor.IActorRef GetCurrentSelfOrNoSender() { } public static Akka.Actor.IActorRef GetCurrentSenderOrNoSender() { } - [System.ObsoleteAttribute("Use TryGetSingleChild [0.7.1]")] public Akka.Actor.IInternalActorRef GetSingleChild(string name) { } public void Init(bool sendSupervise, Akka.Dispatch.MailboxType mailboxType) { } public Akka.Actor.Internal.ChildRestartStats InitChild(Akka.Actor.IInternalActorRef actor) { } @@ -127,7 +126,6 @@ namespace Akka.Actor public void TerminatedQueuedFor(Akka.Actor.IActorRef subject, Akka.Util.Option customMessage) { } public bool TryGetChildStatsByName(string name, out Akka.Actor.Internal.IChildStats child) { } protected bool TryGetChildStatsByRef(Akka.Actor.IActorRef actor, out Akka.Actor.Internal.ChildRestartStats child) { } - public bool TryGetSingleChild(string name, out Akka.Actor.IInternalActorRef child) { } public void UnbecomeStacked() { } protected void UnreserveChild(string name) { } public Akka.Actor.IActorRef Unwatch(Akka.Actor.IActorRef subject) { } @@ -1081,7 +1079,7 @@ namespace Akka.Actor bool IsTerminated { get; } Akka.Actor.IInternalActorRef Parent { get; } Akka.Actor.IActorRefProvider Provider { get; } - Akka.Actor.IActorRef GetChild(System.Collections.Generic.IEnumerable name); + Akka.Actor.IActorRef GetChild(System.Collections.Generic.IReadOnlyList name); void Restart(System.Exception cause); void Resume(System.Exception causedByFailure = null); [System.ObsoleteAttribute("Use SendSystemMessage(message) [1.1.0]")] @@ -1202,7 +1200,7 @@ namespace Akka.Actor public abstract bool IsTerminated { get; } public abstract Akka.Actor.IInternalActorRef Parent { get; } public abstract Akka.Actor.IActorRefProvider Provider { get; } - public abstract Akka.Actor.IActorRef GetChild(System.Collections.Generic.IEnumerable name); + public abstract Akka.Actor.IActorRef GetChild(System.Collections.Generic.IReadOnlyList name); public abstract void Restart(System.Exception cause); public abstract void Resume(System.Exception causedByFailure = null); [System.ObsoleteAttribute("Use SendSystemMessage(message) instead [1.1.0]")] @@ -1245,7 +1243,7 @@ namespace Akka.Actor protected Akka.Actor.IInternalActorRef Supervisor { get; } protected Akka.Actor.ActorSystem System { get; } public override Akka.Actor.ICell Underlying { get; } - public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IEnumerable name) { } + public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IReadOnlyList name) { } public override Akka.Actor.IInternalActorRef GetSingleChild(string name) { } protected virtual Akka.Actor.ActorCell NewActorCell(Akka.Actor.Internal.ActorSystemImpl system, Akka.Actor.IInternalActorRef self, Akka.Actor.Props props, Akka.Dispatch.MessageDispatcher dispatcher, Akka.Actor.IInternalActorRef supervisor) { } public override void Restart(System.Exception cause) { } @@ -1317,7 +1315,7 @@ namespace Akka.Actor [System.ObsoleteAttribute("Use Context.Watch and Receive [1.1.0]")] public override bool IsTerminated { get; } public override Akka.Actor.IInternalActorRef Parent { get; } - public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IEnumerable name) { } + public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IReadOnlyList name) { } public override void Restart(System.Exception cause) { } public override void Resume(System.Exception causedByFailure = null) { } public override void SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage message) { } @@ -1533,7 +1531,7 @@ namespace Akka.Actor public override Akka.Actor.ActorPath Path { get; } public override Akka.Actor.IActorRefProvider Provider { get; } public override Akka.Actor.ICell Underlying { get; } - public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IEnumerable name) { } + public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IReadOnlyList name) { } public override Akka.Actor.IInternalActorRef GetSingleChild(string name) { } public Akka.Actor.RepointableActorRef Initialize(bool async) { } protected virtual Akka.Actor.ActorCell NewCell() { } diff --git a/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt b/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt index 0d3f12af45c..3b90d4f2deb 100644 --- a/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt +++ b/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt @@ -171,7 +171,7 @@ namespace Akka.Remote public override Akka.Actor.IInternalActorRef Parent { get; } public override Akka.Actor.ActorPath Path { get; } public override Akka.Actor.IActorRefProvider Provider { get; } - public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IEnumerable name) { } + public override Akka.Actor.IActorRef GetChild(System.Collections.Generic.IReadOnlyList name) { } public bool IsWatchIntercepted(Akka.Actor.IActorRef watchee, Akka.Actor.IActorRef watcher) { } public override void Restart(System.Exception cause) { } public override void Resume(System.Exception causedByFailure = null) { } diff --git a/src/core/Akka.Remote/RemoteActorRef.cs b/src/core/Akka.Remote/RemoteActorRef.cs index 098f9f6c846..976b6956ec5 100644 --- a/src/core/Akka.Remote/RemoteActorRef.cs +++ b/src/core/Akka.Remote/RemoteActorRef.cs @@ -12,6 +12,7 @@ using Akka.Annotations; using Akka.Dispatch.SysMsg; using Akka.Event; +using Akka.Util.Internal.Collections; namespace Akka.Remote { @@ -106,17 +107,16 @@ public RemoteActorRef(RemoteTransport remote, Address localAddressToUse, ActorPa /// The name. /// ActorRef. /// TBD - public override IActorRef GetChild(IEnumerable name) + public override IActorRef GetChild(IReadOnlyList name) { - var items = name.ToList(); - switch (items.FirstOrDefault()) + switch (name.FirstOrDefault()) { case null: return this; case "..": - return Parent.GetChild(items.Skip(1)); + return Parent.GetChild(name.NoCopySlice(1)); default: - return new RemoteActorRef(Remote, LocalAddressToUse, Path / items, ActorRefs.Nobody, Props.None, Deploy.None); + return new RemoteActorRef(Remote, LocalAddressToUse, Path / name, ActorRefs.Nobody, Props.None, Deploy.None); } } diff --git a/src/core/Akka.Remote/RemoteSystemDaemon.cs b/src/core/Akka.Remote/RemoteSystemDaemon.cs index 1a820b62fb3..2e5fce15820 100644 --- a/src/core/Akka.Remote/RemoteSystemDaemon.cs +++ b/src/core/Akka.Remote/RemoteSystemDaemon.cs @@ -156,11 +156,9 @@ protected override void TellInternal(object message, IActorRef sender) } } - var t = Rec(ImmutableList.Empty); - var concatenatedChildNames = t.Item1; - var m = t.Item2; + var (concatenatedChildNames, m) = Rec(ImmutableList.Empty); - var child = GetChild(concatenatedChildNames); + var child = GetChild(concatenatedChildNames.ToList()); if (child.IsNobody()) { var emptyRef = new EmptyLocalActorRef(_system.Provider, @@ -302,7 +300,7 @@ private void HandleDaemonMsgCreate(DaemonMsgCreate message) /// /// The name. /// ActorRef. - public override IActorRef GetChild(IEnumerable name) + public override IActorRef GetChild(IReadOnlyList name) { var path = name.Join("/"); var n = 0; @@ -313,7 +311,7 @@ public override IActorRef GetChild(IEnumerable name) { if (uid != ActorCell.UndefinedUid && uid != child.Path.Uid) return Nobody.Instance; - return n == 0 ? child : child.GetChild(name.TakeRight(n)); + return n == 0 ? child : child.GetChild(name.TakeRight(n).ToList()); } var last = path.LastIndexOf("/", StringComparison.Ordinal); diff --git a/src/core/Akka.TestKit/TestActorRefBase.cs b/src/core/Akka.TestKit/TestActorRefBase.cs index b440c75f89e..a557d2545fc 100644 --- a/src/core/Akka.TestKit/TestActorRefBase.cs +++ b/src/core/Akka.TestKit/TestActorRefBase.cs @@ -258,7 +258,7 @@ ISurrogate ISurrogated.ToSurrogate(ActorSystem system) bool IInternalActorRef.IsTerminated { get { return _internalRef.IsTerminated; } } - IActorRef IInternalActorRef.GetChild(IEnumerable name) + IActorRef IInternalActorRef.GetChild(IReadOnlyList name) { return _internalRef.GetChild(name); } diff --git a/src/core/Akka.TestKit/TestProbe.cs b/src/core/Akka.TestKit/TestProbe.cs index 31fd374010c..ef586d69042 100644 --- a/src/core/Akka.TestKit/TestProbe.cs +++ b/src/core/Akka.TestKit/TestProbe.cs @@ -124,7 +124,7 @@ ISurrogate ISurrogated.ToSurrogate(ActorSystem system) bool IInternalActorRef.IsTerminated { get { return ((IInternalActorRef)TestActor).IsTerminated; } } - IActorRef IInternalActorRef.GetChild(IEnumerable name) + IActorRef IInternalActorRef.GetChild(IReadOnlyList name) { return ((IInternalActorRef)TestActor).GetChild(name); } diff --git a/src/core/Akka/Actor/ActorCell.Children.cs b/src/core/Akka/Actor/ActorCell.Children.cs index ab59198342d..163418c39db 100644 --- a/src/core/Akka/Actor/ActorCell.Children.cs +++ b/src/core/Akka/Actor/ActorCell.Children.cs @@ -353,58 +353,37 @@ protected bool TryGetChildStatsByRef(IActorRef actor, out ChildRestartStats chil /// /// N/A /// N/A - [Obsolete("Use TryGetSingleChild [0.7.1]")] public IInternalActorRef GetSingleChild(string name) - { - IInternalActorRef child; - return TryGetSingleChild(name, out child) ? child : ActorRefs.Nobody; - } - - - - /// - /// TBD - /// - /// TBD - /// TBD - /// TBD - public bool TryGetSingleChild(string name, out IInternalActorRef child) { if (name.IndexOf('#') < 0) { // optimization for the non-uid case - if (TryGetChildRestartStatsByName(name, out var stats)) + if (ChildrenContainer.TryGetByName(name, out var stats) && stats is ChildRestartStats r) { - child = stats.Child; - return true; + return r.Child; } - else if (TryGetFunctionRef(name, out var functionRef)) + + if (TryGetFunctionRef(name, out var functionRef)) { - child = functionRef; - return true; + return functionRef; } } else { var (s, uid) = GetNameAndUid(name); - if (TryGetChildRestartStatsByName(s, out var stats)) + if (TryGetChildRestartStatsByName(s, out var stats) && (uid == ActorCell.UndefinedUid || uid == stats.Uid)) { - if (uid == ActorCell.UndefinedUid || uid == stats.Uid) - { - child = stats.Child; - return true; - } + return stats.Child; } - else if (TryGetFunctionRef(s, uid, out var functionRef)) + + if (TryGetFunctionRef(s, uid, out var functionRef)) { - child = functionRef; - return true; + return functionRef; } } - child = ActorRefs.Nobody; - return false; + return ActorRefs.Nobody; } - + /// /// TBD /// diff --git a/src/core/Akka/Actor/ActorCell.cs b/src/core/Akka/Actor/ActorCell.cs index 1a3a32a7e3e..d8eabb6c149 100644 --- a/src/core/Akka/Actor/ActorCell.cs +++ b/src/core/Akka/Actor/ActorCell.cs @@ -236,7 +236,7 @@ public void Init(bool sendSupervise, MailboxType mailboxType) [Obsolete("Use TryGetChildStatsByName [0.7.1]", true)] public IInternalActorRef GetChildByName(string name) //TODO: Should return Option[ChildStats] { - return TryGetSingleChild(name, out var child) ? child : ActorRefs.Nobody; + return GetSingleChild(name); } IActorRef IActorContext.Child(string name) diff --git a/src/core/Akka/Actor/ActorRef.cs b/src/core/Akka/Actor/ActorRef.cs index 959da6607cf..ca783f4ad5f 100644 --- a/src/core/Akka/Actor/ActorRef.cs +++ b/src/core/Akka/Actor/ActorRef.cs @@ -19,6 +19,7 @@ using Akka.Event; using Akka.Util; using Akka.Util.Internal; +using Akka.Util.Internal.Collections; namespace Akka.Actor { @@ -422,7 +423,7 @@ public interface IInternalActorRef : IActorRef, IActorRefScope /// /// The path elements. /// The , or if the requested path does not exist, returns . - IActorRef GetChild(IEnumerable name); + IActorRef GetChild(IReadOnlyList name); /// /// Resumes an actor if it has been suspended. @@ -481,7 +482,7 @@ public abstract class InternalActorRefBase : ActorRefBase, IInternalActorRef public abstract IActorRefProvider Provider { get; } /// - public abstract IActorRef GetChild(IEnumerable name); //TODO: Refactor this to use an IEnumerator instead as this will be faster instead of enumerating multiple times over name, as the implementations currently do. + public abstract IActorRef GetChild(IReadOnlyList name); //TODO: Refactor this to use an IEnumerator instead as this will be faster instead of enumerating multiple times over name, as the implementations currently do. /// public abstract void Resume(Exception causedByFailure = null); @@ -530,9 +531,9 @@ public override IInternalActorRef Parent } /// - public override IActorRef GetChild(IEnumerable name) + public override IActorRef GetChild(IReadOnlyList name) { - if (name.All(string.IsNullOrEmpty)) + if (name.All(x => string.IsNullOrEmpty(x))) return this; return ActorRefs.Nobody; } @@ -874,20 +875,17 @@ override def getChild(name: Iterator[String]): InternalActorRef = { /// /// TBD /// TBD - public override IActorRef GetChild(IEnumerable name) + public override IActorRef GetChild(IReadOnlyList name) { //Using enumerator to avoid multiple enumerations of name. - var enumerator = name.GetEnumerator(); - if (!enumerator.MoveNext()) - { - //name was empty + if (name.Count == 0) return this; - } - var firstName = enumerator.Current; + + var firstName = name[0]; if (string.IsNullOrEmpty(firstName)) return this; if (_children.TryGetValue(firstName, out var child)) - return child.GetChild(new Enumerable(enumerator)); + return child.GetChild(name.NoCopySlice(1)); return ActorRefs.Nobody; } diff --git a/src/core/Akka/Actor/ActorRefProvider.cs b/src/core/Akka/Actor/ActorRefProvider.cs index 0c9cd6dd3f1..aa6e21adb95 100644 --- a/src/core/Akka/Actor/ActorRefProvider.cs +++ b/src/core/Akka/Actor/ActorRefProvider.cs @@ -462,7 +462,7 @@ public IActorRef ResolveActorRef(ActorPath path) /// TBD /// TBD /// TBD - internal IInternalActorRef ResolveActorRef(IInternalActorRef actorRef, IReadOnlyCollection pathElements) + internal IInternalActorRef ResolveActorRef(IInternalActorRef actorRef, IReadOnlyList pathElements) { if (pathElements.Count == 0) { diff --git a/src/core/Akka/Actor/LocalActorRef.cs b/src/core/Akka/Actor/LocalActorRef.cs index 10e4f298b46..11e9f6cad9d 100644 --- a/src/core/Akka/Actor/LocalActorRef.cs +++ b/src/core/Akka/Actor/LocalActorRef.cs @@ -12,6 +12,7 @@ using Akka.Dispatch; using Akka.Dispatch.SysMsg; using Akka.Util.Internal; +using Akka.Util.Internal.Collections; namespace Akka.Actor { @@ -52,7 +53,8 @@ public class LocalActorRef : ActorRefWithCell, ILocalRef /// TBD /// TBD /// TBD - public LocalActorRef(ActorSystemImpl system, Props props, MessageDispatcher dispatcher, MailboxType mailboxType, IInternalActorRef supervisor, ActorPath path) + public LocalActorRef(ActorSystemImpl system, Props props, MessageDispatcher dispatcher, MailboxType mailboxType, + IInternalActorRef supervisor, ActorPath path) { _system = system; _props = props; @@ -61,18 +63,19 @@ public LocalActorRef(ActorSystemImpl system, Props props, MessageDispatcher disp _supervisor = supervisor; _path = path; - /* - * Safe publication of this class’s fields is guaranteed by Mailbox.SetActor() - * which is called indirectly from ActorCell.init() (if you’re wondering why - * this is at all important, remember that under the CLR readonly fields are only - * frozen at the _end_ of the constructor, but we are publishing "this" before - * that is reached). - * This means that the result of NewActorCell needs to be written to the field - * _cell before we call init and start, since we can start using "this" - * object from another thread as soon as we run init. - */ + /* + * Safe publication of this class’s fields is guaranteed by Mailbox.SetActor() + * which is called indirectly from ActorCell.init() (if you’re wondering why + * this is at all important, remember that under the CLR readonly fields are only + * frozen at the _end_ of the constructor, but we are publishing "this" before + * that is reached). + * This means that the result of NewActorCell needs to be written to the field + * _cell before we call init and start, since we can start using "this" + * object from another thread as soon as we run init. + */ // ReSharper disable once VirtualMemberCallInConstructor - _cell = NewActorCell(_system, this, _props, _dispatcher, _supervisor); // _cell needs to be assigned before Init is called. + _cell = NewActorCell(_system, this, _props, _dispatcher, + _supervisor); // _cell needs to be assigned before Init is called. _cell.Init(true, MailboxType); } @@ -206,19 +209,17 @@ protected override void TellInternal(object message, IActorRef sender) /// public override IInternalActorRef GetSingleChild(string name) { - IInternalActorRef child; - return _cell.TryGetSingleChild(name, out child) ? child : ActorRefs.Nobody; + return _cell.GetSingleChild(name); } /// - public override IActorRef GetChild(IEnumerable name) + public override IActorRef GetChild(IReadOnlyList name) { - var current = (IActorRef)this; + IActorRef current = this; int index = 0; - foreach (string element in name) + foreach (var element in name) { - var currentLocalActorRef = current as LocalActorRef; - if (currentLocalActorRef != null) + if (current is LocalActorRef currentLocalActorRef) { switch (element) { @@ -232,20 +233,21 @@ public override IActorRef GetChild(IEnumerable name) break; } } - else + else if (current is IInternalActorRef internalActorRef) { //Current is not a LocalActorRef - if (current != null) - { - var rest = name.Skip(index).ToList(); - return current.AsInstanceOf().GetChild(rest); - } + var rest = name.NoCopySlice(index); + return internalActorRef.GetChild(rest); + } + else // not a LocalActorRef or an IInternalActorRef + { throw new NotSupportedException("Bug, we should not get here"); } + index++; } + return current; } } -} - +} \ No newline at end of file diff --git a/src/core/Akka/Actor/RepointableActorRef.cs b/src/core/Akka/Actor/RepointableActorRef.cs index 6933f23da21..31ccb2f872e 100644 --- a/src/core/Akka/Actor/RepointableActorRef.cs +++ b/src/core/Akka/Actor/RepointableActorRef.cs @@ -15,6 +15,7 @@ using Akka.Dispatch.SysMsg; using Akka.Event; using Akka.Pattern; +using Akka.Util.Internal.Collections; namespace Akka.Actor { @@ -278,17 +279,16 @@ protected override void TellInternal(object message, IActorRef sender) /// /// TBD /// TBD - public override IActorRef GetChild(IEnumerable name) + public override IActorRef GetChild(IReadOnlyList name) { - var current = (IActorRef)this; - if (!name.Any()) return current; + if (name.Count == 0) return this; - var next = name.FirstOrDefault() ?? ""; + var next = name[0]; switch (next) { case "..": - return Parent.GetChild(name.Skip(1)); + return Parent.GetChild(name.NoCopySlice(1)); case "": return ActorRefs.Nobody; default: @@ -297,8 +297,8 @@ public override IActorRef GetChild(IEnumerable name) { if (stats is ChildRestartStats crs && (uid == ActorCell.UndefinedUid || uid == crs.Uid)) { - if (name.Skip(1).Any()) - return crs.Child.GetChild(name.Skip(1)); + if (name.Count > 1) + return crs.Child.GetChild(name.NoCopySlice(1)); else return crs.Child; } diff --git a/src/core/Akka/Util/Internal/Collections/ListSlice.cs b/src/core/Akka/Util/Internal/Collections/ListSlice.cs new file mode 100644 index 00000000000..5614b6a05b7 --- /dev/null +++ b/src/core/Akka/Util/Internal/Collections/ListSlice.cs @@ -0,0 +1,182 @@ +// //----------------------------------------------------------------------- +// // +// // Copyright (C) 2009-2021 Lightbend Inc. +// // Copyright (C) 2013-2021 .NET Foundation +// // +// //----------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Akka.Util.Internal.Collections +{ + internal static class SliceExtensions + { + public static IReadOnlyList NoCopySlice(this IReadOnlyList list, int offset) + { + switch (list) + { + // slice of a slice + case ListSlice slice: + { + return new ListSlice(slice.Array, slice.Offset + offset, slice.Array.Count - slice.Offset - offset); + } + default: + { + return new ListSlice(list, offset, list.Count - offset); + } + } + } + } + + /// + /// but for + /// + /// + internal struct ListSlice : IList, IReadOnlyList + { + private sealed class SliceEnumerator : IEnumerator + { + private readonly IReadOnlyList _array; + private readonly int _start; + private readonly int _end; + private int _current; + + public SliceEnumerator(ListSlice array) + { + _array = array._array; + _start = array.Offset; + _end = _start + array.Count; + _current = _start - 1; + } + + public bool MoveNext() + { + if (_current < _end) + { + _current++; + return (_current < _end); + } + return false; + } + + public void Reset() + { + _current = _start - 1; + } + + public T Current + { + get + { + if (_current < _start) throw new InvalidOperationException("Enumeration not started."); + if (_current >= _end) throw new InvalidOperationException("Enumeration ended."); + return _array[_current]; + } + } + + object IEnumerator.Current => Current; + + public void Dispose() + { + + } + } + + private readonly IReadOnlyList _array; + + public ListSlice(IReadOnlyList array) + { + + if (array == null) + throw new ArgumentNullException(nameof(array)); + + _array = array; + Offset = 0; + Count = array.Count; + } + + public ListSlice(IReadOnlyList array, int offset, int count) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be below zero."); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), "Cannot be below zero."); + + _array = array; + Offset = offset; + Count = count; + } + + public int Offset { get; } + + public IReadOnlyList Array => _array; + + public IEnumerator GetEnumerator() + { + return new SliceEnumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(T item) + { + throw new System.NotImplementedException(); + } + + public void Clear() + { + throw new System.NotImplementedException(); + } + + public bool Contains(T item) + { + throw new System.NotImplementedException(); + } + + public void CopyTo(T[] array, int arrayIndex) + { + var n = 0; + foreach (var i in _array.Skip(Offset).Take(Count)) + { + array[arrayIndex + n++] = i; + } + } + + public bool Remove(T item) + { + throw new System.NotImplementedException(); + } + + public int Count { get; } + + public bool IsReadOnly => true; + public int IndexOf(T item) + { + throw new System.NotImplementedException(); + } + + public void Insert(int index, T item) + { + throw new System.NotImplementedException(); + } + + public void RemoveAt(int index) + { + throw new System.NotImplementedException(); + } + + public T this[int index] + { + get => _array[Offset + index]; + set => throw new System.NotImplementedException(); + } + } +} \ No newline at end of file