/// <summary>
        /// Serialize linked list and write to file stream.
        /// </summary>
        /// <param name="fs">File stream for writing serialized list</param>
        /// <param name="list">Linked list to serialize</param>
        public static void Serialize(FileStream fs, ListRand list)
        {
            Dictionary <ListNode, int> nodeToIndex = GetNodeToIndex(list);
            string listJson = GetListJson(list, nodeToIndex);

            byte[] bytes = new UTF8Encoding(true).GetBytes(listJson);
            fs.Write(bytes, 0, bytes.Length);
        }
 /// <summary>
 /// Restore linked list fields and node references.
 /// </summary>
 /// <param name="list">Linked list to restore</param>
 /// <param name="nodeInfos">List of NodeInfo with nodes and their field values</param>
 private static void FillList(ListRand list, List <NodeInfo> nodeInfos)
 {
     if (nodeInfos.Count <= 0)
     {
         return;
     }
     ConnectNodes(nodeInfos);
     list.Head  = nodeInfos.First().Node;
     list.Tail  = nodeInfos.Last().Node;
     list.Count = nodeInfos.Count;
 }
        /// <summary>
        /// Create a dictionary where each node is paired with it's index, if it was a simple array.
        /// Stop creating dictionary when next node is null or hit cycle.
        /// </summary>
        /// <param name="list">Linked list</param>
        /// <returns>Dictionary with nodes paired with their indexes</returns>
        private static Dictionary <ListNode, int> GetNodeToIndex(ListRand list)
        {
            Dictionary <ListNode, int> nodeToIndex = new Dictionary <ListNode, int>();
            ListNode node  = list.Head;
            int      index = 0;

            while (node != null && !nodeToIndex.ContainsKey(node))
            {
                nodeToIndex.Add(node, index++);
                node = node.Next;
            }

            return(nodeToIndex);
        }
        /// <summary>
        /// Deserialize linked list from file stream.
        /// </summary>
        /// <param name="fs">File stream to read from</param>
        /// <param name="list">List to deserialize to</param>
        /// <exception cref="UnexpectedEndException">Thrown when reach end of stream before finished deserializing</exception>
        /// <exception cref="UnexpectedCharException">Thrown when found unexpected char</exception>
        public static void Deserialize(FileStream fs, ListRand list)
        {
            CheckStreamBeginning(fs);

            List <NodeInfo> nodeInfos = new List <NodeInfo>();
            bool            readNode  = false;

            while (true)
            {
                int b = fs.ReadByte();

                if (b == '{' && !readNode)
                {
                    readNode = true;
                    nodeInfos.Add(DeserializeNode(fs));
                }
                else if (b == ',' && readNode)
                {
                    readNode = false;
                }
                else if (b == -1)
                {
                    throw new UnexpectedEndException();
                }
                else if (b == ']')
                {
                    break;
                }
                else
                {
                    throw new UnexpectedCharException((char)b);
                }
            }

            FillList(list, nodeInfos);
        }
        /// <summary>
        /// Write list with all nodes to string in json format.
        /// Stop writing json when next node is null or hit cycle.
        /// </summary>
        /// <param name="list">List to write to json</param>
        /// <param name="nodeToIndex">Dictionary with nodes paired with their indexes</param>
        /// <returns>List in json format</returns>
        private static string GetListJson(ListRand list, Dictionary <ListNode, int> nodeToIndex)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("[");
            HashSet <ListNode> visitedNodes = new HashSet <ListNode>();
            ListNode           node         = list.Head;

            while (node != null)
            {
                visitedNodes.Add(node);
                WriteNode(node, sb, nodeToIndex);
                node = node.Next;
                if (node == null || visitedNodes.Contains(node))
                {
                    break;
                }

                sb.Append(",");
            }

            sb.Append("]");
            return(sb.ToString());
        }