Use C # Build a Generics LinkedList

Catalog

Generics Introduction

Generic compiler mechanism of C#

default Keyword in Generic Code

How to Create a Simple Generics Classes.

How to Create a Generic Method

The Different between Generics LinkedList and Non-Generics LinkedList

The Code of Generics LinkedList

The Code of Non-Generics LinkedList

Reference

 

 

Use C # Build a Generics LinkedList

 

Generics Introduction

The Generics in C# is that to operate many data types on the same code through parameterized type. Generic programming is a programming model, which used parameterized type to abstract the type for more flexible reuse. Generic classes and methods combine reusability, type safety and efficiency in a way that their non-generic counterparts cannot.

Generic compiler mechanism of C#

At the first time of compiler, the compiler type LinkedList for a generic version of the IL code and metadata will not give any examples of generic types, T in the middle only to act as a placeholder.

   At the JIT compiler, when JIT compiler LinkedList met for the first time, int type will be used to replace the generic version of the IL code and metadata of T - for generic examples of the type.

   CLR for all types of parameters, to the reference type of generic types have the same code, but if the parameters of the type is the value types, each a different type of value, CLR will be generated for a separate code.

The following example from the first compiler of Node<T> is shows the first compiler of a generics class.

.class private auto ansi beforefieldinit Node<T>
    
    
    extends [mscorlib]System.Object
  
  
{
    
    
    .method public hidebysig specialname rtspecialname instance void .ctor(!T data) cil managed
   
   
    {
    
    
        .maxstack 8
    
    
        L_0000: ldarg.0 
    
    
        L_0001: call instance void [mscorlib]System.Object::.ctor()
    
    
        L_0006: nop 
    
    
        L_0007: nop 
    
    
        L_0008: ldarg.0 
    
    
        L_0009: ldarg.1 
    
    
        L_000a: stfld !0 MyLinkedList.Node`1<!T>::data
  
  
        L_000f: ldarg.0 
    
    
        L_0010: ldnull 
    
    
        L_0011: stfld class MyLinkedList.Node`1<!0> MyLinkedList.Node`1<!T>::next
  
  
        L_0016: nop 
    
    
        L_0017: ret 
    
    
    }
    
    

  
  
   
    
  
  
    .method public hidebysig specialname rtspecialname instance void .ctor(!T data, class MyLinkedList.Node`1<!T> next) cil managed
   
   
    {
    
    
        .maxstack 8
    
    
        L_0000: ldarg.0 
    
    
        L_0001: call instance void [mscorlib]System.Object::.ctor()
    
    
        L_0006: nop 
    
    
        L_0007: nop 
    
    
        L_0008: ldarg.0 
    
    
        L_0009: ldarg.1 
    
    
        L_000a: stfld !0 MyLinkedList.Node`1<!T>::data
  
  
        L_000f: ldarg.0 
    
    
        L_0010: ldarg.2 
    
    
        L_0011: stfld class MyLinkedList.Node`1<!0> MyLinkedList.Node`1<!T>::next
  
  
        L_0016: nop 
    
    
        L_0017: ret 
    
    
    }
    
    

  
  
   
    
  
  

  
  
   
    
  
  
    .property instance !T Data
   
   
    {
    
    
        .get instance !T MyLinkedList.Node`1::get_Data()
    
    
        .set instance void MyLinkedList.Node`1::set_Data(!T)
    
    
    }
    
    

  
  
   
    
  
  
    .property instance class MyLinkedList.Node`1<!T> Next
   
   
    {
    
    
        .get instance class MyLinkedList.Node`1<!T> MyLinkedList.Node`1::get_Next()
    
    
        .set instance void MyLinkedList.Node`1::set_Next(class MyLinkedList.Node`1<!T>)
    
    
    }
    
    

  
  
   
    
  
  

  
  
   
    
  
  
    .field private !T data
    
    

  
  
   
    
  
  
    .field private class MyLinkedList.Node`1<!T> next
    
    

  
  
   
    
  
  

}

default Keyword in Generic Code

In generic classes and methods, one issue that arises is how to assign a default value to a parameterized type T when you do not know the following in advance:

  1. Whether T will be a reference type or a value type.
  2. If T is a value type, whether it will be a numeric value or a struct.

Given a variable t of a parameterized type T, the statement t = null is only valid if T is a reference type and t = 0 will only work for numeric value types but not for structs. The solution is to use the default keyword, which will return null for reference types and zero for numeric value types. For structs, it will return each member of the structs initialized to zero or null depending on whether they are value or reference types.

The following example from the LinkedList<T> class shows how to use the default keyword.

public T RemoveFromHead()

{

     if (IsEmpty)

        return default(T);

     Node<T> temp = head;

     head = head.Next;

     count--;

     return temp.Data;

 }

How to Create a Simple Generics Classes

Typically, you create generic classes by starting with an existing concrete class, and changing types into type parameters one at a time until you reach the optimal balance of generalization and usability.

following example from the Test<T> class shows how to create a generics class.

class Test<T>
{

    private T data;

public Test(){}

public Test(T data){

    this.data = data;

}

}

T is the parameter type. Throughout the above code, the data type for the Node is T rather than any specific types like int or string or any other class. This gives flexibility to the programmer to use this class with any data type he wishes to use.The following example is shows how to create a Non-Geneics classes.

class Test

{

    private object data;

public Test(){}

public Test(object data){

    this.data = data;

}

}

How to Create a Generic Method

A generic method is a method that is declared with a type parameter.

The following example shows the method with generics parameter:

/// <summary>

/// AddToHead() used to Add an elements to the head of LinkedList

/// </summary>

/// <param name="data"></param>

public void AddToHead(T data)

{

   Node<T> node = new Node<T>(data);

   node.Next = head;

   head = node;

   count++;

}

The following example shows the generic method.

/// <summary>

/// RemoveFromHead() used to delete an elements from LinkedList

/// </summary>

/// <returns></returns>

public T RemoveFromHead()

{

    if (IsEmpty)

       return default(T);

    Node<T> temp = head;

    head = head.Next;

    count--;

    return temp.Data;

}

The Different between Generics LinkedList and Non-Generics LinkedList

The generics LinkedList is type safety and efficient,because it is not boxing and unboxing,and it isn’t type conversion.

For example:

LinkedList list = new LinkedList();

List. AddToHead(1);

List.AddToHead(“tom”);

foreach(int i in list)s{

int number = i;

}

 

The top code is no error while compiling,but it is occur an error during run-time.You can use the code like this:

LinkedList<int> list = new LinkedList<int>();

list.AddToHead(1);

list.AddToHead(2);

//list. AddToHead ("cumtkang"); //occur an error during compiling

foreach(int i in list){

int number = i;

}

 

From the two examples. We found that the first example be boxing and unboxing and casting. Both the casting and the boxing and unboxing operations degrade performance; the effect of boxing and unboxing can be quite significant in scenarios where you must iterate over large collections.

The Code of Generics LinkedList

 

using System;

using System.Collections.Generic;

 

namespace MyLinkedList

{

    /// <summary>

    /// Node class

    /// </summary>

    /// <typeparam name="T"></typeparam>

    class Node<T>

    {

        private T data;

        private Node<T> next;

        /// <summary>

        /// Constructor

        /// </summary>

        /// <param name="data">The data of Node</param>

        public Node(T data)

        {

            this.data = data;

            this.next = null;

        }

        /// <summary>

        /// Constructor

        /// </summary>

        /// <param name="data">the data of Node</param>

        /// <param name="next">Next Node</param>

        public Node(T data, Node<T> next)

        {

            this.data = data;

            this.next = next;

        }

 

        /// <summary>

        /// Set and Get the data from a Node class

        /// </summary>

        public T Data

        {

            set { this.data = value; }

            get { return this.data; }

        }

 

        /// <summary>

        /// Set and Get the Next Node

        /// </summary>

        public Node<T> Next

        {

            set { this.next = value; }

            get { return this.next; }

        }

    }

 

    class LinkedList<T>

    {

        protected int count;   //the variable count used to mask the //LinkedList's length

        protected Node<T> head;    

        /// <summary>

        /// Constructor

        /// </summary>

public LinkedList()   //LinkList Constructor

        {

            head = null;

            count = 0;

        }

 

        /// <summary>

        /// the property IsEmpty used to judge the LinkedList is NULL or not.

        /// </summary>

        public bool IsEmpty

        {

            get { return count==0; }

        }

 

        /// <summary>

        /// AddToHead() used to Add an elements to the head of LinkedList

        /// </summary>

        /// <param name="data"></param>

        public void AddToHead(T data)

        {

            Node<T> node = new Node<T>(data);

            node.Next = head;

            head = node;

            count++;

        }

 

        /// <summary>

        /// RemoveFromHead() used to delete an element from head

        /// </summary>

        /// <returns></returns>

        public T RemoveFromHead()

        {

            if (IsEmpty)

                return default(T);

            Node<T> temp = head;

            head = head.Next;

            count--;

            return temp.Data;

        }

 

        /// <summary>

        /// The method Peek() used to get the LinkedList head elements.

        /// </summary>

        /// <returns></returns>

        public T Peek()

        {

            if (IsEmpty)

                return default(T);

            return head.Data;

        }

 

        /// <summary>

        /// The method AddToTail() used to add an elements to Tail.

        /// </summary>

        /// <param name="data"></param>

        public void AddToTail(T data)

        {

            Node<T> temp = new Node<T>(data, null);

            if (head != null)

            {

                Node<T> finger = head;//Point to the head Node

                while (finger.Next!= null)                {

                    finger = finger.Next;

                }

                finger.Next = temp;

            }

            else head = temp;//If the LinkedList is NULL,the last Node is first //Node,too.

            count++;

        }

 

        /// <summary>

        /// The method RemoveFromTail() used to delete elements from Tail

        /// </summary>

        /// <returns></returns>

        public T RemoveFromTail()

        {

            if (IsEmpty)

                return default(T);

            Node<T> finger = head;

            Node<T> previous = null;

            while (finger.Next != null)

            {

                previous = finger;

                finger = finger.Next;

            }

            if (previous == null)

            {

                head = null;

            }

            else

            {

                previous.Next = null;

            }

            count--;

            return finger.Data;

        }

 

        /// <summary>

        /// The method Contains() used to judge the elements is in the LinkedList ///or not

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public bool Contains(T data)

        {

            if (!IsEmpty)

            {

                Node<T> finger = head;

                while (finger != null && !finger.Data.Equals(data))

                {

                    finger = finger.Next;

                }

                return finger != null;

            }

            else

            {

                Console.WriteLine("LinkedList is Empty");

                return false;

            }

        }

 

        /// <summary>

        /// The method Remove() used to delete elements from LinkedList

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public T Remove(T data)

        {

            Node<T> finger = head;

            Node<T> previous = null;

            while (finger != null && !finger.Next.Equals(data))

            {

                previous = finger;

                finger = finger.Next;

            }

            if (finger != null)

            {

                if (previous == null)

                {

                    head = finger.Next;

                }

                else

                {

                    previous.Next = finger.Next;

                }

                count--;

                return finger.Data;

            }

            return default(T);

        }

 

        /// <summary>

        ///  The method clear() used to clear LinkedList

        /// </summary>

        public void clear()

        {

            head = null;

            count = 0;

        }

 

        /// <summary>

        /// Count elements

        /// </summary>

        public int Count

        {

            get { return this.count; }

        }

 

        public IEnumerator<T> GetEnumerator()

        {

            Node<T> current = head;

            while (current != null)

            {

                yield return current.Data;

                current = current.Next;

            }

        }  

 }

}

The Code of Non-Generics LinkedList

using System;

using System.Collections;

 

namespace MyLinkedList

{

    class Node

    {

        private object data;

        private Node next;

 

        public Node(object data)

        {

            this.data = data;

            this.next = null;

        }

        public Node(object data, Node next)

        {

            this.data = data;

            this.next = next;

        }

 

        public object Data

        {

            set { this.data = value; }

            get { return this.data; }

        }

 

        public Node Next

        {

            set { this.next = value; }

            get { return this.next; }

        }

    }

 

    class LinkedList

    {

        protected int count;   //variable count used mask LinkedList Length.

        protected Node head;   //LinkedList head

        public LinkedList()   //Constructor

        {

            head = null;

            count = 0;

        }

 

        /// <summary>

        /// Proporty IsEmpty used to judge the LinkedList is null or not

        /// </summary>

        public bool IsEmpty

        {

            get { return count == 0; }

        }

 

        /// <summary>

        /// AddToHead() used to add an elements into LinkedList

        /// </summary>

        /// <param name="data"></param>

        public void AddToHead(object data)

        {

            Node node = new Node(data);

            node.Next = head;

            head = node;

            count++;

        }

 

        /// <summary>

        /// RemoveFromHead() used to delete an elements from head

        /// </summary>

        /// <returns></returns>

        public object RemoveFromHead()

        {

            if (IsEmpty)

                return null;

            Node temp = head;

            head = head.Next;

            count--;

            return temp.Data;

        }

 

        /// <summary>

        /// Peek() used to return the head elements

        /// </summary>

        /// <returns></returns>

        public object Peek()

        {

            if (IsEmpty)

                return null;

            return head.Data;

        }

 

        /// <summary>

        /// AddToTail() used to add an elements into Tail

        /// </summary>

        /// <param name="data"></param>

        public void AddToTail(object data)

        {

            Node temp = new Node(data, null);

            if (head != null)

            {

                Node finger = head;//Point to the head Node

                while (finger.Next != null)

                {

                    finger = finger.Next;

                }

                finger.Next = temp;

            }

            else head = temp;//if the LinkedList is null,the head Node is last //Node

            count++;

        }

 

        /// <summary>

        /// RemoveFromTail() used to delete an elements from Tail.

        /// </summary>

        /// <returns></returns>

        public object RemoveFromTail()

        {

            if (IsEmpty)

                return null;

            Node finger = head;

            Node previous = null;

            while (finger.Next != null)

            {

                previous = finger;

                finger = finger.Next;

            }

            if (previous == null)

            {

                head = null;

            }

            else

            {

                previous.Next = null;

            }

            count--;

            return finger.Data;

        }

 

        /// <summary>

        /// Contains() used to judge there is an elements in LinkedList or not.

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public bool Contains(object data)

        {

            if (!IsEmpty)

            {

                Node finger = head;

                while (finger != null && !finger.Data.Equals(data))

                {

                    finger = finger.Next;

                }

                return finger != null;

            }

            else

            {

                Console.WriteLine("The LinkedList is null.");

                return false;

            }

        }

 

        /// <summary>

        /// Remove() used to delete an elements from LinkedList.

        /// </summary>

        /// <param name="data"></param>

        /// <returns></returns>

        public object Remove(object data)

        {

            Node finger = head;

            Node previous = null;

            while (finger != null && !finger.Next.Equals(data))

            {

                previous = finger;

                finger = finger.Next;

            }

            if (finger != null)

            {

                if (previous == null)

                {

                    head = finger.Next;

                }

                else

                {

                    previous.Next = finger.Next;

                }

                count--;

                return finger.Data;

            }

            return null;

        }

 

        /// <summary>

        /// clear() used to clear the LinkedList.

        /// </summary>

        public void clear()

        {

            head = null;

            count = 0;

        }

 

        /// <summary>

        /// Count the elements of LinkedList

        /// </summary>

        public int Count

        {

            get { return this.count; }

        }

      

   public IEnumerator GetEnumerator()

   {

       Node current = head;

       while (current != null)

       {

            yield return current.Data;

            current = current.Next;

        }

    }

    }

 

    public class Program

    {

        static void Main(string[] args)

        {

            LinkedList list = new LinkedList();

            list.AddToHead("kangyi");

            list.AddToTail("cumt");

            list.AddToHead("kang");

            list.AddToTail("cumtkang");

            Console.WriteLine(list.Count);

            Console.WriteLine(list.Peek());

            foreach (string s in list)

            {

                Console.WriteLine(s);

            }

        }

    }

}

 

Reference

1、  Microsoft .NET Framework 2.0 Documentation.

2、  Learning the Development of C# Through Examples

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值