c# 泛型的理解
理解泛型
是的,我知道泛型(Generics)并不是.NET 3.5的新特性。但是,它对LINQ to SQL来说是相当重要的部分,值得我们花点篇幅来回顾。
注意:
要使用泛型,你需要引入System.Collections.Generic命名空间。
我使用泛型的绝大多数情况,是由于泛型集合。例如,如果想描述一个字符串列表,你可以这样声明(C#):
List<string> stuffToBuy = new List<string>();
stuffToBuy.Add(“socks”);
stuffToBuy.Add(“beer”);
stuffToBuy.Add(“cigars”);
使用VB.NET,则这样声明:
Dim stuffToBuy As New List(Of String)
stuffToBuy.Add(“socks”)
stuffToBuy.Add(“beer”)
stuffToBuy.Add(“cigars”)
现在,利用集合初始化器,你可以仅用一行代码就声明一个强类型的字符串列表(C#):
List<string> stuffToBuy2 = new List<string> {“socks”, “beer”, “cigars”};
注意:VB.NET并不支持集合或数组初始化器。
List 类是泛型类,因为在声明的时候指定了它要包含的对象的类型。C#中,要在尖括号之间(< >)指定类型,而在VB.NET中要使用Of关键字。在上例中,我们创建了一个包含字符串的List类。同样地 ,我们也可以创建包含整型或其他自定义类型(如Product和Customer类,分别代表产品和顾客)的List类。
因为泛型是强类型 的,因此泛型集合(如List)优于非泛型集合(如ArrayList)。ArrayList将所有对象都保存为object,而泛型将所有对象保存为它 们特定的类型。当从ArrayList中取出一个对象时,在使用该对象前你必须将其转换为特定类型。而从泛型中取出对象则不需要这种转换。
泛型并不仅仅局限于集合。你可以创建泛型方法、泛型类以及泛型接口。
例如,当使用ADO.NET时,我喜欢将data reader转换为强类型的List集合。如Listing 18.4所示,GetListFromCommand()方法包含一个command对象,执行该对象,然后自动生成一个强类型的List。
代码清单 18-4 LanguageChanges\App_Code\GenericMethods.cs
using System; using System.Collections.Generic; using System.Data.SqlClient; public class GenericMethods { public static List<T> GetListFromCommand<T>(SqlCommand command) where T: ICreatable, new() { List<T> results = new List<T>(); using (command.Connection) { command.Connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { T newThing = new T(); newThing.Create(reader); results.Add(newThing); } } return results; } } public interface ICreatable { void Create(SqlDataReader reader); }代码清单18-4中的GetListFromCommand()方法接收一个SqlCommand对象并且返回一个泛 型List<T>。where子句用来约束泛型类型。泛型约束使得类型T必须实现ICreatable接口并且可以通过new实例化(准确的 意思应为,必须包含无参的构造函数。——译者注)。
代码清单18-4中同样定义了ICreatable接口,它要求类实现Create()方法。
既然我们创建了可以将data reader 转换为强类型的list的泛型方法,那么我们就可以用它处理任何实现了ICreatable接口的类,如代码清单18-5中的Movie类。
代码清单 18-5 Movie.cs
using System; using System.Data.SqlClient; public class Movie : ICreatable { public int Id { get; set; } public string Title { get; set; } public void Create(SqlDataReader reader) { Id = (int)reader[“Id”]; Title = (string)reader[“Title”]; } }你可以通过下面的方法调用GetListFromCommand()方法(随书CD中的ShowGenericMethods.aspx页面使用了该代码):
string conString = WebConfigurationManager.ConnectionStrings[“con”].ConnectionString; SqlConnection con = new SqlConnection(conString); SqlCommand cmd = new SqlCommand(“SELECT Id, Title FROM Movie”, con); List<Movie> movies = GenericMethods.GetListFromCommand<Movie>(cmd);在这里,泛型的出色之处在于,你不必为每个类型编写相同的代码将data reader 转换为泛型List。你只编写了一个泛型方法GetListFromCommand(),却可以用该方法转换任何复合泛型约束的类型。
理解泛型的正确方法是理解代码模板。你可以使用泛型来定义某一代码模式,而将一个特定的类应用与该模式中。
c# 泛型的理解