private static XChannel AddXChannel(LinkedList <XChannel> list, ChannelIdentification identification, object?targetId, bool exclusiveChannel, IWeakDelegate weakDelegate)
        { // lock (cs) required.
            if (exclusiveChannel)
            {
                if (list.Count > 0)
                { // other channel already exists.
                    throw new InvalidOperationException();
                }
            }
            else
            {
                if (list.First?.Value.ExclusiveChannel == true)
                { // Exclusive channel exists.
                    throw new InvalidOperationException();
                }
            }

            // New XChannel
            var channel = new XChannel(identification, targetId, exclusiveChannel, weakDelegate);

            // list: Identification to XChannels.
            channel.Node = list.AddLast(channel);

            return(channel);
        }
        private static XChannel[] PrepareXChannelArray(LinkedList <XChannel> list, object?targetId)
        { // lock (cs) required. Convert LinkedList to Array, release garbage collected object, and increment reference count.
            var array      = new XChannel[list.Count];
            var arrayCount = 0;
            var node       = list.First;
            LinkedListNode <XChannel>?nextNode;

            if (targetId == null)
            {
                while (node != null)
                {
                    nextNode = node.Next;

                    if (node.Value.IsAlive)
                    {// The instance is still alive.
                        array[arrayCount++] = node.Value;
                    }
                    else if (node.Value.ReferenceCount == 0)
                    {// The instance is garbage collected and reference count is 0.
                        CloseChannel(node.Value);
                    }

                    node = nextNode;
                }
            }
            else
            {
                while (node != null)
                {
                    nextNode = node.Next;

                    if (node.Value.IsAlive)
                    {// The instance is still alive.
                        if (node.Value.TargetId == targetId)
                        {
                            array[arrayCount++] = node.Value;
                        }
                    }
                    else if (node.Value.ReferenceCount == 0)
                    {// Garbage collected and reference count is 0.
                        CloseChannel(node.Value);
                    }

                    node = nextNode;
                }
            }

            if (array.Length != arrayCount)
            {
                Array.Resize(ref array, arrayCount);
            }

            foreach (var x in array)
            {
                x.ReferenceCount++;
            }

            return(array);
        }
        private static void CloseChannel(XChannel channel)
        {// lock (cs) required. Reference count must be 0.
            // list: Identification to XChannels.
            if (channel.Node != null)
            {
                var list = channel.Node.List;
                if (list != null)
                {
                    list.Remove(channel.Node);
                }
            }

            channel.MarkForDeletion();
        }
        public static void Close(XChannel channel)
        {
            if (channel.Disposed == true)
            {// already closed.
                return;
            }

            while (true)
            {
                lock (cs)
                {
                    if (channel.ReferenceCount == 0)
                    {// reference countが0(Send / Receive処理をしていない状態)になったら、Close
                        CloseChannel(channel);
                        break;
                    }
                }
#if NETFX_CORE
                Task.Delay(50).Wait();
#else
                System.Threading.Thread.Sleep(50);
#endif
            }
        }