[英]Nullable Types as Generics
我正在嘗試為我的個人圖書館創建一個可以處理所有內容的鏈表。 我正在嘗試編寫它,以便它可以“平等地”輕松地將int
, null
, DateTime
或Class
傳遞給我,並且我希望它可以輕松地擴展,以便如果我想快速地從中取出堆棧,我可以編寫push
, pop
和peek
方法等等。
目前,我的代碼如下所示。 請注意,我將“ 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.