所谓泛型是指将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。 例如:通常一个方法或过程的签名都是有明确的数据类型的。 如 : public void ProcessData(int i){} public void ProcessData(string i){} public void ProcessData(decimal i){} public void ProcessData(double i){} 等。 这些方法的签名中的:int ,string,decimal,double 都是明确的数据类型,程序员访问这些方法的过程中需要提供提定类型的参数: ProcessData(123); ProcessData("abc"); ProcessData("12.12") 而如果我们将int ,string,decimal,double这些类型也当成一种参数传给方法的时候方法的定义便是这样: public void ProcessData<T>(T i){} //T是int ,string,decimal,double这些数据类型的指代 用户在调用的时候便成了这样: ProcessData<string>("abc"); ProcessData<int>(123); ProcessData<double>(12.23); 这与通常的那些定义的最大区别是,方法的定义实现过程只有一个。但是它具有处理不同的数据类型数据的能力。 C# 2.0中有如List<>等泛型对象都具有此特性。 具有泛型机制的软件开发平台及语言 .Net 平台 2.0及以上版本 JAVA 5及以上版本 泛型的好处: 泛型是c#2.0的一个新增加的特性,它为使用c#语言编写面向对象程序增加了极大的效力和灵活性。它允许程序员将一个实际的数据类型的规约延迟至泛型的实例被创建时才确定。泛型为开发者提供了一种高性能的编程方式,能够提高代码的重用性,并允许开发者编写非常优雅的解决方案。
// Declare the generic class public class GenericList<T> { void Add(T input) { } } class TestGenericList { private class ExampleClass { } static void Main() { // Declare a list of type int GenericList<int> list1 = new GenericList<int>(); // Declare a list of type string GenericList<string> list2 = new GenericList<string>(); // Declare a list of type ExampleClass GenericList<ExampleClass> list3 = new GenericList<ExampleClass>(); } }
泛型 一、什么是泛型? 通过泛型可以定义类型安全类,而不会损害类型安全、性能或工作效率 二、实例化泛型 1、可以使用任何类型来声明和实例化 2、申明和实例话都必须用一个特定的类型来代替一般类型T 3、例子: //原来写法 Public class Stack { object[] m_Items; public void Push(object item) {...} public object Pop() {...} } Stack stack = new Stack(); stack.Push(1); int number = (int)stack.Pop(); //有了泛型后 Public class Stack <T> { T[] m_Items; public void Push(T item) {...} public T Pop() {...} } Stack <int> stack = new Stack <int> (); stack.Push(1); int number = (int)stack.Pop(); 三:泛型的好处 1、一次性的开发、测试和部署代码,通过任何类型来重用它 2、编译器支持和类型安全 3、不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。 注:值类型大概可以提高200%,引用类型大概为100% 四:多个泛型 1、单个类型可以定义多个泛型 五:泛型别名 1、在文件头部使用using 为特定类型取别名,别名作用范围是整个文件 2、例子 using List = LinkedList <int,string> ; class ListClient { static void Main(string[] args) { List list = new List(); list.AddHead(123, "AAA "); } } 五:泛型约束 (1)、派生约束 如: public class LinkedList <K,T> where K:IComparable { T Find(K key) { if (str.Key.CompareTo(key) == 0)//只有实现这个接口才可比较 } } 注意: 1、所有的派生约束必须放在类的实际派生列表之后 如:public class LinkedList <K,T> :IEnumerable <T> where K:IComparable <K> {...} 2、一个泛型参数上可以约束多个接口(用逗号分隔) public class LinkedList <K,T> where K:IComparable <K> ,IConvertible 3、在一个约束中最多只能使用一个基类 4、约束的基类不能是密封类或静态类 5、不能将System.Delegate或System.Array约束为基类 6、可以同时约束一个基类以及一个或多个接口,但是该基类必须首先出现在派生约束列表中。 7、C#允许你将另一个泛型参数指定为约束 public class MyClass <T,U> where T:U {...} 8、可以自己定义基类或接口进行泛型约束 9、自定义的接口或基类必须与泛型具有一致的可见性 (2)、构造函数约束 如: class Node <K,T> where T:new() { } 注意: 1、可以将构造函数的约束和派生约束结合起来,前提是构造函数的约束出现在约束列表中的最后 (3)、引用/值类型约束 1、可以使用struct约束将泛型参数约束为值类型(如int、bool、enum),或任何自定义结构 2、同样可以使用class约束将泛型参数约束为引用类型 3、不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类 4、不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类 5、虽然您可以使用类和默认构造函数约束,但是这样做没有任何价值 6、可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束出现在约束列表的开头 六:泛型和强制类型转换 1、C#编译器只允许将泛型参数隐式转换到Object或约束指定的类型 如: interface IS{...} class BaseClass{...} class MyClass <T> where T:BaseClass,IS { void SomeMethod(T t) { IS obj1 = t; BaseClass obj2 = t; object obj3 = t; } } 2、编译器允许你将泛型参数显示强制转换到其他任何借口,但不能将其转换到类 interface IS{...} class SomeClass{...} class MyClass <T> //没有约束 { void SomeMethod(T t) { IS obj1 = (IS)t; //可以 SomeClass obj2 = (SomeClass)t //不可以 } } 3、可以使用临时的Object变量,将泛型参数强制转换到其他任何类型 class SomeClass{...} class MyClass <T> { void SomeMethod(T t) { object temp = t; SomeClass obj = (SomeClass)temp;//可以 } } 注意:这里只是告诉你这样写是可以的,但是要不要这样写?不要这样写,因为如果t确实没有继承SomeClass编译没错但是运行就会出错 4、解决上面强制转换问题,可以使用is和as运算符进行判断 public class MyClass <T> { public void SomeMethod <T t> { if (t is int ){...} if (t is LinkedList <int,string> ){...} //如果泛型参数的类型是所查询的类型,则is运算符返回true string str = t as string; //如果这写类型兼容,则as将执行强制类型转换,否则将返回null if (str != null){...} LinkedList <int,string> list = t as LinkedList <int,string> ; if (list != null){...} } } 七:继承和泛型 1、在从泛型基类派生,可以提供类型实参,而不是基类泛型参数 public class BaseClass <T> {...} public class SubClass:BaseClass <int> 2、如果子类是泛型,而非具体的类型实参,则可以使用子类泛型参数作为泛型基类的指定类型 public class BaseClass <TT> {...} public class SubClass <T> :BaseClass <T> {...} 3、在使用子类泛型参数时,必须在子类级别重复在基类级别规定的任何约束 4、基类可以定义其签名使用泛型参数的虚礼方法,在重写它们时,子类必须在方法签名中提供相应的类型。 如: public class BaseClass <T> { public virtual T SomeMethod() {...} } public class SubClass:BaseClass <int> { public override int SomeMethod() {...} } 5、如果该子类是泛型,则它还可以在重写时使用它自己的泛型参数 public class SubClass <T> :BaseClass <T> { public override T SomeMethod() {...} } 6、你可以定义泛型接口、泛型抽象类,甚至泛型抽象方法。 7、不能对泛型参数使用+或+=之类的运算符 public class Calculator <T> { public T Add (T arg1,T arg2) { return arg1 + arg2;//错误 } } 但是我们可以通过泛型抽象类、接口来实现在个功能,因为实现泛型抽象类、接口我们就已经明确传一个参数了,就可以执行诸如+这样的操作。 八:泛型方法 1、方法可以定义特定于其执行范围的泛型参数 public class MyClass <T> { public void MyMethod <X> (X x) {...} } 2、即使各包含类根本不使用泛型,你也可以定义方法特定的泛型参数 public class MyClass { public void MyMethod <T> (T t) {...} } 注意:该功能只使用于方法,属性,索引器只能使用在类的作用范围中定义的泛型参数。 3、调用泛型方法 MyClass obj = new MyClass(); obj.MyMethod <int> (3); 也可以这样: MyClass obj = new MyClass(); obj.MyMethod(3); //该功能称为泛型推理 4、泛型方法也可以有自己的泛型参数约束 pubic class MyClass { public void SomeMethod <T> (T t) where T:IComparable <T> {...} } 5、子类方法实现不能重复在父级别出现的约束 public class BaseClass { public virtual void SomeMethod <T> (T t)where T:new() {...} } pubic class SubClass:BaseClass { public override void SomeMethod <T> (T t)//不能再有约束 {...} } 6、静态方法 静态方法可以定义特定的泛型参数和约束 public class MyClass <T> { public static T SomeMethod <X> (T t,X x) {...} } int number = MyClass <int> .SomeMethod <string> (3, "AAA "); 或者:int mumber = MyClass <int> .SomeMethod(3, "AAA "); 九:泛型委托 1、在某个类中定义的委托可以利用该类的泛型参数 2、委托也可以定义自己的泛型参数
2.0 版 C# 语言和公共语言运行库 (CLR) 中增加了泛型。泛型将类型参数的概念引入 .NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。例如,通过使用泛型类型参数 T,您可以编写其他客户端代码能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险,如下所示: // type parameter T in angle brackets public class GenericList<T> { // The nested class is also generic on T. private class Node { // T used in non-generic constructor. public Node(T t) { next = null; data = t; } private Node next; public Node Next { get { return next; } set { next = value; } } // T as private member data type. private T data; // T as return type of property. public T Data { get { return data; } set { data = value; } } } private Node head; // constructor public GenericList() { head = null; } // T as method parameter type: public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator<T> GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } } } 下面的代码示例演示客户端代码如何使用泛型 GenericList<T> 类来创建整数列表。只需更改类型参数,即可方便地修改下面的代码示例,创建字符串或任何其他自定义类型的列表: class TestGenericList { static void Main() { // int is the type argument GenericList<int> list = new GenericList<int>(); for (int x = 0; x < 10; x++) { list.AddHead(x); } foreach (int i in list) { System.Console.Write(i + " "); } System.Console.WriteLine("\nDone"); } }
// type parameter T in angle brackets public class GenericList<T> { // The nested class is also generic on T. private class Node { // T used in non-generic constructor. public Node(T t) { next = null; data = t; } private Node next; public Node Next { get { return next; } set { next = value; } } // T as private member data type. private T data; // T as return type of property. public T Data { get { return data; } set { data = value; } } } private Node head; // constructor public GenericList() { head = null; } // T as method parameter type: public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator<T> GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } } }class TestGenericList { static void Main() { // int is the type argument GenericList<int> list = new GenericList<int>(); for (int x = 0; x < 10; x++) { list.AddHead(x); } foreach (int i in list) { System.Console.Write(i + " "); } System.Console.WriteLine("\nDone"); } }
例如:通常一个方法或过程的签名都是有明确的数据类型的。
如 :
public void ProcessData(int i){}
public void ProcessData(string i){}
public void ProcessData(decimal i){}
public void ProcessData(double i){}
等。
这些方法的签名中的:int ,string,decimal,double 都是明确的数据类型,程序员访问这些方法的过程中需要提供提定类型的参数:
ProcessData(123);
ProcessData("abc");
ProcessData("12.12")
而如果我们将int ,string,decimal,double这些类型也当成一种参数传给方法的时候方法的定义便是这样:
public void ProcessData<T>(T i){} //T是int ,string,decimal,double这些数据类型的指代
用户在调用的时候便成了这样:
ProcessData<string>("abc");
ProcessData<int>(123);
ProcessData<double>(12.23);
这与通常的那些定义的最大区别是,方法的定义实现过程只有一个。但是它具有处理不同的数据类型数据的能力。
C# 2.0中有如List<>等泛型对象都具有此特性。
具有泛型机制的软件开发平台及语言
.Net 平台 2.0及以上版本
JAVA 5及以上版本
泛型的好处:
泛型是c#2.0的一个新增加的特性,它为使用c#语言编写面向对象程序增加了极大的效力和灵活性。它允许程序员将一个实际的数据类型的规约延迟至泛型的实例被创建时才确定。泛型为开发者提供了一种高性能的编程方式,能够提高代码的重用性,并允许开发者编写非常优雅的解决方案。
public class GenericList<T>
{
void Add(T input) { }
}
class TestGenericList
{
private class ExampleClass { }
static void Main()
{
// Declare a list of type int
GenericList<int> list1 = new GenericList<int>(); // Declare a list of type string
GenericList<string> list2 = new GenericList<string>(); // Declare a list of type ExampleClass
GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
}
}
一、什么是泛型?
通过泛型可以定义类型安全类,而不会损害类型安全、性能或工作效率 二、实例化泛型
1、可以使用任何类型来声明和实例化
2、申明和实例话都必须用一个特定的类型来代替一般类型T
3、例子:
//原来写法
Public class Stack
{
object[] m_Items;
public void Push(object item)
{...}
public object Pop()
{...}
}
Stack stack = new Stack();
stack.Push(1);
int number = (int)stack.Pop(); //有了泛型后
Public class Stack <T>
{
T[] m_Items;
public void Push(T item)
{...}
public T Pop()
{...}
}
Stack <int> stack = new Stack <int> ();
stack.Push(1);
int number = (int)stack.Pop(); 三:泛型的好处
1、一次性的开发、测试和部署代码,通过任何类型来重用它
2、编译器支持和类型安全
3、不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。
注:值类型大概可以提高200%,引用类型大概为100% 四:多个泛型
1、单个类型可以定义多个泛型 五:泛型别名
1、在文件头部使用using 为特定类型取别名,别名作用范围是整个文件
2、例子
using List = LinkedList <int,string> ;
class ListClient
{
static void Main(string[] args)
{
List list = new List();
list.AddHead(123, "AAA ");
}
} 五:泛型约束
(1)、派生约束
如:
public class LinkedList <K,T> where K:IComparable
{
T Find(K key)
{
if (str.Key.CompareTo(key) == 0)//只有实现这个接口才可比较
}
} 注意:
1、所有的派生约束必须放在类的实际派生列表之后
如:public class LinkedList <K,T> :IEnumerable <T> where K:IComparable <K>
{...}
2、一个泛型参数上可以约束多个接口(用逗号分隔)
public class LinkedList <K,T> where K:IComparable <K> ,IConvertible
3、在一个约束中最多只能使用一个基类
4、约束的基类不能是密封类或静态类
5、不能将System.Delegate或System.Array约束为基类
6、可以同时约束一个基类以及一个或多个接口,但是该基类必须首先出现在派生约束列表中。
7、C#允许你将另一个泛型参数指定为约束
public class MyClass <T,U> where T:U
{...}
8、可以自己定义基类或接口进行泛型约束
9、自定义的接口或基类必须与泛型具有一致的可见性 (2)、构造函数约束
如:
class Node <K,T> where T:new()
{
}
注意:
1、可以将构造函数的约束和派生约束结合起来,前提是构造函数的约束出现在约束列表中的最后 (3)、引用/值类型约束
1、可以使用struct约束将泛型参数约束为值类型(如int、bool、enum),或任何自定义结构
2、同样可以使用class约束将泛型参数约束为引用类型
3、不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类
4、不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类
5、虽然您可以使用类和默认构造函数约束,但是这样做没有任何价值
6、可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束出现在约束列表的开头 六:泛型和强制类型转换
1、C#编译器只允许将泛型参数隐式转换到Object或约束指定的类型
如:
interface IS{...}
class BaseClass{...}
class MyClass <T> where T:BaseClass,IS
{
void SomeMethod(T t)
{
IS obj1 = t;
BaseClass obj2 = t;
object obj3 = t;
}
}
2、编译器允许你将泛型参数显示强制转换到其他任何借口,但不能将其转换到类
interface IS{...}
class SomeClass{...}
class MyClass <T> //没有约束
{
void SomeMethod(T t)
{
IS obj1 = (IS)t; //可以
SomeClass obj2 = (SomeClass)t //不可以
}
}
3、可以使用临时的Object变量,将泛型参数强制转换到其他任何类型
class SomeClass{...}
class MyClass <T>
{
void SomeMethod(T t)
{
object temp = t;
SomeClass obj = (SomeClass)temp;//可以
}
}
注意:这里只是告诉你这样写是可以的,但是要不要这样写?不要这样写,因为如果t确实没有继承SomeClass编译没错但是运行就会出错
4、解决上面强制转换问题,可以使用is和as运算符进行判断
public class MyClass <T>
{
public void SomeMethod <T t>
{
if (t is int ){...}
if (t is LinkedList <int,string> ){...}
//如果泛型参数的类型是所查询的类型,则is运算符返回true
string str = t as string;
//如果这写类型兼容,则as将执行强制类型转换,否则将返回null
if (str != null){...}
LinkedList <int,string> list = t as LinkedList <int,string> ;
if (list != null){...}
}
} 七:继承和泛型
1、在从泛型基类派生,可以提供类型实参,而不是基类泛型参数
public class BaseClass <T> {...}
public class SubClass:BaseClass <int>
2、如果子类是泛型,而非具体的类型实参,则可以使用子类泛型参数作为泛型基类的指定类型
public class BaseClass <TT> {...}
public class SubClass <T> :BaseClass <T> {...}
3、在使用子类泛型参数时,必须在子类级别重复在基类级别规定的任何约束
4、基类可以定义其签名使用泛型参数的虚礼方法,在重写它们时,子类必须在方法签名中提供相应的类型。
如:
public class BaseClass <T>
{
public virtual T SomeMethod()
{...}
}
public class SubClass:BaseClass <int>
{
public override int SomeMethod()
{...}
}
5、如果该子类是泛型,则它还可以在重写时使用它自己的泛型参数
public class SubClass <T> :BaseClass <T>
{
public override T SomeMethod()
{...}
}
6、你可以定义泛型接口、泛型抽象类,甚至泛型抽象方法。
7、不能对泛型参数使用+或+=之类的运算符
public class Calculator <T>
{
public T Add (T arg1,T arg2)
{
return arg1 + arg2;//错误
}
}
但是我们可以通过泛型抽象类、接口来实现在个功能,因为实现泛型抽象类、接口我们就已经明确传一个参数了,就可以执行诸如+这样的操作。 八:泛型方法
1、方法可以定义特定于其执行范围的泛型参数
public class MyClass <T>
{
public void MyMethod <X> (X x)
{...}
}
2、即使各包含类根本不使用泛型,你也可以定义方法特定的泛型参数
public class MyClass
{
public void MyMethod <T> (T t)
{...}
}
注意:该功能只使用于方法,属性,索引器只能使用在类的作用范围中定义的泛型参数。
3、调用泛型方法
MyClass obj = new MyClass();
obj.MyMethod <int> (3);
也可以这样:
MyClass obj = new MyClass();
obj.MyMethod(3); //该功能称为泛型推理
4、泛型方法也可以有自己的泛型参数约束
pubic class MyClass
{
public void SomeMethod <T> (T t) where T:IComparable <T>
{...}
}
5、子类方法实现不能重复在父级别出现的约束
public class BaseClass
{
public virtual void SomeMethod <T> (T t)where T:new()
{...}
}
pubic class SubClass:BaseClass
{
public override void SomeMethod <T> (T t)//不能再有约束
{...}
}
6、静态方法
静态方法可以定义特定的泛型参数和约束
public class MyClass <T>
{
public static T SomeMethod <X> (T t,X x)
{...}
}
int number = MyClass <int> .SomeMethod <string> (3, "AAA ");
或者:int mumber = MyClass <int> .SomeMethod(3, "AAA "); 九:泛型委托
1、在某个类中定义的委托可以利用该类的泛型参数
2、委托也可以定义自己的泛型参数
// type parameter T in angle brackets
public class GenericList<T>
{
// The nested class is also generic on T.
private class Node
{
// T used in non-generic constructor.
public Node(T t)
{
next = null;
data = t;
} private Node next;
public Node Next
{
get { return next; }
set { next = value; }
} // T as private member data type.
private T data; // T as return type of property.
public T Data
{
get { return data; }
set { data = value; }
}
} private Node head; // constructor
public GenericList()
{
head = null;
} // T as method parameter type:
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
} public IEnumerator<T> GetEnumerator()
{
Node current = head; while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
下面的代码示例演示客户端代码如何使用泛型 GenericList<T> 类来创建整数列表。只需更改类型参数,即可方便地修改下面的代码示例,创建字符串或任何其他自定义类型的列表:
class TestGenericList
{
static void Main()
{
// int is the type argument
GenericList<int> list = new GenericList<int>(); for (int x = 0; x < 10; x++)
{
list.AddHead(x);
} foreach (int i in list)
{
System.Console.Write(i + " ");
}
System.Console.WriteLine("\nDone");
}
}
我发现很多人只要是说泛型就马上说:知道,不就是List<T>吗
这样真是严重误解了泛型
http://www.cnblogs.com/snow365/articles/1234830.html
/// <summary>
/// 根据属性名称,在obj对象里查找属性,并返回属性的值(返回obj.propertyName的值)
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyName">属性名(区分大小写)</param>
/// <returns></returns>
public static object GetValue(object obj, string propertyName)
{
object l_ret; System.Reflection.PropertyInfo info =
obj.GetType().GetProperty(propertyName,
System.Reflection.BindingFlags.GetProperty |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance);
if (info != null)
{
l_ret = info.GetValue(obj, null);
}
else
{
l_ret = null;
}
return l_ret;
}/// <summary>
/// 根据属性名称,在obj对象里查找属性,并设置属性的值
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyName">属性名(区分大小写)</param>
/// <param name="propertyValue">属性值</param>
/// <returns></returns>
public static void SetValue(object obj, string propertyName, object propertyValue)
{
System.Reflection.PropertyInfo info =
obj.GetType().GetProperty(propertyName,
System.Reflection.BindingFlags.GetProperty |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance);
//System.Reflection.BindingFlags.IgnoreCase |
if (info != null)
{
info.SetValue(obj, propertyValue, null);
}
}/// <summary>
/// 把子类转换成父类返回
/// 注:extendType 必须是baseType类型的子类
/// </summary>
/// <typeparam name="baseType">要返回的父类类型,必须具有无参的构造函数</typeparam>
/// <typeparam name="extendType">传入的子类类型</typeparam>
/// <param name="obj">要转换的对象</param>
/// <returns></returns>
public static baseType TransToBase<baseType, extendType>(extendType obj)
where baseType : new()
where extendType : baseType
{
baseType l_ret = new baseType();
System.Reflection.PropertyInfo[] l_arrProperty = typeof(baseType).GetProperties(System.Reflection.BindingFlags.GetProperty |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance);
foreach (System.Reflection.PropertyInfo property in l_arrProperty)
{
object l_propertyValue = property.GetValue(obj, null);
property.SetValue(l_ret, l_propertyValue, null);
}
return l_ret;
}
http://www.cnblogs.com/abatei/category/122163.html?Show=All
public class GenericList<T>
{
// The nested class is also generic on T.
private class Node
{
// T used in non-generic constructor.
public Node(T t)
{
next = null;
data = t;
} private Node next;
public Node Next
{
get { return next; }
set { next = value; }
} // T as private member data type.
private T data; // T as return type of property.
public T Data
{
get { return data; }
set { data = value; }
}
} private Node head; // constructor
public GenericList()
{
head = null;
} // T as method parameter type:
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
} public IEnumerator<T> GetEnumerator()
{
Node current = head; while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}class TestGenericList
{
static void Main()
{
// int is the type argument
GenericList<int> list = new GenericList<int>(); for (int x = 0; x < 10; x++)
{
list.AddHead(x);
} foreach (int i in list)
{
System.Console.Write(i + " ");
}
System.Console.WriteLine("\nDone");
}
}