簡體   English   中英

可空類型作為泛型

[英]Nullable Types as Generics

我正在嘗試為我的個人圖書館創建一個可以處理所有內容的鏈表。 我正在嘗試編寫它,以便它可以“平等地”輕松地將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下顯示紅色文本,表示“類型'int'必須是引用類型,才能在通用類型或方法--- this ---中將其用作參數'Base'。

告訴我您是否要刪除評論,我不確定是否更難或更容易解決。

因為您聲明了將Base類型限制為類( 引用類型 ),所以:

public class LinkedList<Base> where Base : class

它究竟是禁止使用的Int32,因為它是一個值類型不同的 ,從所需的引用類型。

new LinkedList<Int32>()

因此,要解決此特定問題,您將需要為整數值創建一個包裝器類。

但是,在執行此操作之前,請檢查您打算在鏈接列表中存儲任何類型的意圖。 這樣做將剝奪C#作為強類型語言的所有優勢。

如前所述,除非您僅將此代碼作為純粹的學術練習來編寫,否則,如果需要更多功能,則應使用現有的.NET LinkedList並可能對其進行擴展/繼承。

更新:我以為它不用多說,但是要弄清楚,別忘了Nullable是一個struct ,而不是一個class ,所以您不能像int那樣使用“作弊”?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM