可空类型作为泛型

时间:2015-06-30 23:45:48

标签: c# linked-list

我正在尝试为我的个人库创建一个可以处理所有内容的链接列表。我试着写它,以便它可以同样地#'轻松地intnullDateTimeClass,我希望它可以轻松扩展,这样如果我想快速制作堆栈,我可以写pushpoppeek等方法。

目前,我的代码看起来像这样。请注意,我使用' Base'作为我的通用类型。

namespace ClassLibrary1
{
    public class LinkedList<Base> where Base : class
    {
        public class Node
        {
            private Node next;
            private Node prev;
            private Base value;

            /// <summary>
            /// Constructor for Nodes of Circular Linked List class.
            /// Calls overloaded constructor for no previous or next provided.
            /// O(1)
            /// </summary>
            /// <param name="value">The value to be stored. Can use tuple for associations</param>
            public Node(Base value)
            {
                    new Node(null, null, value);
            }

            /// <summary>
            /// Constructor for nodes of Circular Linked List class.
            /// O(1)
            /// </summary>
            /// <param name="prev">The previous node in the linked list</param>
            /// <param name="next">The next node in the linked list</param>
            /// <param name="value">The value to be stored</param>
            public Node(Node prev, Node next, Base value)
            {
                this.prev = prev;
                this.next = next;
                this.value = value;
            }
            /// <summary>
            /// Sets the  'next' attribute of the node to the passed value.
            /// O(1)
            /// Chainable
            /// </summary>
            /// <param name="next">The new value of the 'next' attribute.</param>
            /// <returns>Chainable(Node, this)</returns>
            public Node setNext(Node next)
            {
                this.next = next;
                return this;
            }

            /// <summary>
            /// Sets the 'prev' attribute of the node to the passed value 
            /// O(1)
            /// Chainable
            /// </summary>
            /// <param name="prev">The new value of the 'prev' attribute to denote the previous node</param>
            /// <returns>Chainable(Node, this)</returns>
            public Node setPrev(Node prev)
            {
                this.prev = prev;
                return this;
            }

            /// <summary>
            /// Changes the stored value of type Base to the passed value.
            /// O(1)
            /// Chainable
            /// </summary>
            /// <param name="value">The new value to be stored with the node</param>
            /// <returns>Chainable(Node, this)</returns>
            public Node setVal(Base value)
            {
                this.value = value;
                return this;
            }

            /// <summary>
            /// Returns the next node in the linked list.
            /// O(1)
            /// </summary>
            /// <returns>The next node in the linked list.(Node)</returns>
            public Node getNext()
            {
                return this.next;
            }

            /// <summary>
            /// Returns the previous node in the linked list.
            /// O(1)
            /// </summary>
            /// <returns>The previous node in the linked list.(Node)</returns>
            public Node getPrev()
            {
                return this.prev;
            }

            /// <summary>
            /// Returns the value stored at this node.
            /// O(1)
            /// </summary>
            /// <returns>The value stored at this node.(Base)</returns>
            public Base getVal()
            {
                return this.value;
            }
        }
        public Node head;
        public bool duplicates;
        public bool hasNullValues;
        public bool throwNullError;

        /// <summary>
        /// Constructor for the LinkedList. Creates a null head node.
        /// Duplication defaulted to false
        /// O(1)
        /// </summary>
        public LinkedList()
        {
            this.head = new Node(null);
            this.head.setNext(this.head).setPrev(this.head);
            this.duplicates = false;
            this.hasNullValues = false;
            this.throwNullError = false;
        }

        /// <summary>
        /// Allows duplication for the linked list.
        /// O(1)
        /// Chainable attribute.
        /// </summary>
        /// <returns>Chainable.(LinkedList<Base>, this)</returns>
        public LinkedList<Base> hasDuplicates()
        {
            this.duplicates = true;
            return this;
        }

        /// <summary>
        /// Allows the structure to store null values in nodes.
        /// O(1)
        /// Chainable.
        /// </summary>
        /// <returns>Chainable.(LinkedList<Base>, this)</returns>
        public LinkedList<Base> hasNulls()
        {
            this.hasNullValues = true;
            return this;
        }

        /// <summary>
        /// Causes the structure to throw a null error when a null value is inserted.
        /// If hasNulls is off, turns it on.
        /// O(1)
        /// Chainable.
        /// </summary>
        /// <returns>Chainable.(LinkedList<Base>, this)</returns>
        public LinkedList<Base> throwsNulls()
        {
            if (!this.hasNullValues)
            {
                this.hasNullValues = true;
            }
            this.throwNullError = true;
            return this;
        }

        /// <summary>
        /// Iff duplicates not allowed, searches for value in list. Throws error if duplicate found.
        /// Creates a new node at the end of the list, then links it to the head node.
        /// O(length) [if hasDuplicates()]
        /// O(1) [if else]
        /// Chainable
        /// </summary>
        /// <param name="value">Value stored at the new node in the list</param>
        /// <returns>Chainable.(LinkedList<Base>, this)</returns>
        public LinkedList<Base> add(Base value)
        {
            if (!duplicates)
            {
                if (search(value) != null)
                {
                    throw new Exception("Value already exists in the linked list.");
                }
            }
            if (!this.hasNullValues && value != null)
            {
                if (this.throwNullError)
                {
                    throw new Exception("Cannot insert null values");
                }
                else
                {
                    return this;
                }
            }
            Node newNode = new Node(value);
            this.head.getPrev().setNext(newNode);
            this.head.setPrev(newNode);
            return this;
        }

        /// <summary>
        /// Iterates through the list until first such node for with a matching value is found.
        /// Returns null if no matches found. 
        /// Use searchAll to find duplicates. 
        /// O(length)
        /// </summary>
        /// <param name="value">The value to be searched for.</param>
        /// <returns>First node with the desired value(Node?)</returns>
        public Node search(Base value)
        {
            Node temp = this.head.getNext();
            while (!temp.getVal().Equals(value))
            {
                if (temp.Equals(this.head))
                {
                    return null;
                }
                temp = temp.getNext();
            }
            return temp;
        }

        /// <summary>
        /// If value doesn't exist in the list, throws an exception.
        /// Deletes the first node found with the chosen value.
        /// Use DeleteAll to delete all instances.
        /// Chainable.
        /// O(length)
        /// </summary>
        /// <param name="value">Value to be removed from the list.</param>
        /// <returns>Chainable.(LinkedList<Base>, this)</returns>
        public LinkedList<Base> delete(Base value)
        {
            try{
                return delete(search(value));
            }
            catch(Exception e){
                throw new Exception("Node to be deleted not found");
            }

        }

        /// <summary>
        /// Removes all pointers to the passed node.
        /// O(1)
        /// </summary>
        /// <param name="tbd">The node to be deleted.</param>
        /// <returns>Chainable.(LinkedList<Base>, this)</returns>
        public LinkedList<Base> delete(Node tbd)
        {
            if (tbd.Equals(this.head))
            {
                throw new Exception("Cannot delete head node");
            }
            else
            {
                tbd.getPrev().setNext(tbd.getNext());
                tbd.getNext().setPrev(tbd.getPrev());
            }
            return this;
        }

        /// <summary>
        /// Returns a LinkedList of all nodes containing the desired value.
        /// O(length)
        /// </summary>
        /// <param name="value">The value to be found.</param>
        /// <returns>A LinkedList of Nodes with matching values.(LinkedList<Node>)</returns>
        public LinkedList<Node> searchAll(Base value)
        {
            LinkedList<Node> returnList = new LinkedList<Node>();
            Node temp = this.head.getNext();
            while (!temp.Equals(this.head))
            {
                if (temp.getVal().Equals(value))
                {
                    returnList.add(temp);
                }
                temp = temp.getNext();
            }
            return returnList;
        }

        /// <summary>
        /// Returns the first Node in the Linked List.
        /// O()
        /// </summary>
        /// <returns>First non-head node in the list.(Node)</returns>
        public Node firstOrDefault()
        {
            return this.head.getNext();
        }

        /// <summary>
        /// Returns the value of the first node in the list.
        /// O(1)
        /// </summary>
        /// <returns>FIrst non-head </returns>
        public Base firstVal()
        {
            return this.head.getNext().getVal();
        }

        /// <summary>
        /// Gets the last node in the linked list.
        /// O(1)
        /// </summary>
        /// <returns>The last node in the linked list.(Node)</returns>
        public Node tail()
        {
            return this.head.getPrev();
        }

        /// <summary>
        /// Returns the value of the last node in the linked list.
        /// O(1)
        /// </summary>
        /// <returns>VThe value of the tail node.(Base)</returns>
        public Base tailVal()
        {
            return this.head.getPrev().getVal();
        }

        public static void Main()
        {
            LinkedLis t<Int32> mine = new LinkedList<Int32>();
        }
    }
}

但是,它会在Int32下面显示红色文字,说&#34;类型&#39; int&#39;必须是参考类型才能将其用作参数&#39; Base&#39;在通用类型或方法---这---。

告诉我您是否希望我删除评论,我不确定这是否会使解决更难或更容易。

1 个答案:

答案 0 :(得分:2)

因为您将Base类型的约束声明为类(reference type):

public class LinkedList<Base> where Base : class

它完全禁止使用Int32,因为它是value type并且是different来自所需的引用类型。

new LinkedList<Int32>()

因此,要解决此特定问题,您需要为整数值创建一个包装类。

在此之前,请检查您的意图,以便在链接列表中存储任何类型。这样做,您将剥夺C#作为强类型语言的所有优点。

正如前面提到的,除非你把这段代码写成纯粹的学术练习,否则你应该使用现有的.NET LinkedList,如果你需要更多的功能,可以扩展/继承它。

更新:我认为不言而喻,但为了清楚起见,请不要忘记Nullablestruct,而不是{{1}所以你不能使用&#34;作弊&#34;喜欢int?。