LINQ(Language Integrated Query,語言集成查詢),在C#語言中集成了查詢語法,可以用相同的語法訪問不同的數據源。 LINQ提供了不同數據源的抽象層,所以可以使用相同的語法。 這裡主要介紹LINQ的核心原理和C#中支持C# LINQ查詢的語言擴展。 1.語法 使用LINQ查 ...
LINQ(Language Integrated Query,語言集成查詢),在C#語言中集成了查詢語法,可以用相同的語法訪問不同的數據源。
LINQ提供了不同數據源的抽象層,所以可以使用相同的語法。
這裡主要介紹LINQ的核心原理和C#中支持C# LINQ查詢的語言擴展。
1.語法
使用LINQ查詢出來自巴西的所以世界冠軍。這裡可以使用List<T>類的FindAll()方法,但使用LINQ查詢語法更簡單
static void LINQQuery() { // var query = from r in Formula1.GetChampions() where r.Country == "Brazil" orderby r.Wins descending select r; foreach (var r in query) { Console.WriteLine("{0:A}", r); } }
變數query只指定了LINQ查詢。該查詢不是通過這個賦值語句執行的,而是使用foreach迴圈訪問查詢時執行的。
2.擴展方法
編譯器會轉換LINQ查詢,以調用方法而不是LINQ查詢。LINQ為IEnumerable<T>介面提供了各種擴展方法(擴展方法在http://www.cnblogs.com/afei-24/p/6703843.html介紹到),以便用戶在實現了該介面的任意集合上使用LINQ查詢。
定義LINQ擴展方法的一個類是System.Linq名稱空間中的Enumerable。只需要導入這個名稱空間,就打開了這個類的擴展方法的作用域。下麵是Where()擴展方法的實現代碼:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource,bool> predicate) { foreach(TSource item in source) { if(predicate(item)) { yield return item; } } }
因為Where()作為一個泛型方法,所以它可以用於包含在集合中的任意類型。實現了IEnumerable<T>介面的任意集合都支持它。
3.推遲查詢的執行
前面提到,在運行期間定義LINQ查詢表達式時,查詢不會運行。查詢在迭代數據項時才會運行。
舉個例子:
static void DeferredQuery() { var names = new List<string> { "Nino", "Alberto", "Juan", "Mike", "Phil" }; var namesWithJ = from n in names where n.StartsWith("J") orderby n select n; Console.WriteLine("First iteration"); foreach (string name in namesWithJ) { Console.WriteLine(name); } Console.WriteLine(); names.Add("John"); names.Add("Jim"); names.Add("Jack"); names.Add("Denny"); Console.WriteLine("Second iteration"); foreach (string name in namesWithJ) { Console.WriteLine(name); } }
輸出:
因為查詢在迭代時才執行,所以在第一次輸出後有添加項再輸出,會顯示又添加的項。
但在調用方法ToArray(),ToList等方法時,不會延遲執行:
static void NotDeferredQuery() { var names = new List<string> { "Nino", "Alberto", "Juan", "Mike", "Phil" }; var namesWithJ = (from n in names where n.StartsWith("J") orderby n select n).ToList(); Console.WriteLine("First iteration"); foreach (string name in namesWithJ) { Console.WriteLine(name); } Console.WriteLine(); names.Add("John"); names.Add("Jim"); names.Add("Jack"); names.Add("Denny"); Console.WriteLine("Second iteration"); foreach (string name in namesWithJ) { Console.WriteLine(name); } }
輸出:
下麵是用到的類,後續的也需要用到這些代碼。
//這個類創建需要的列表 public static class Formula1 { private static List<Racer> racers; //返回一組賽車手 public static IList<Racer> GetChampions() { if (racers == null) { racers = new List<Racer>(40); racers.Add(new Racer("Nino", "Farina", "Italy", 33, 5,
new int[] { 1950 }, new string[] { "Alfa Romeo" })); racers.Add(new Racer("Alberto", "Ascari", "Italy", 32, 10,
new int[] { 1952, 1953 }, new string[] { "Ferrari" })); racers.Add(new Racer("Juan Manuel", "Fangio", "Argentina", 51, 24,
new int[] { 1951, 1954, 1955, 1956, 1957 }, new string[] { "Alfa Romeo", "Maserati", "Mercedes", "Ferrari" })); racers.Add(new Racer("Mike", "Hawthorn", "UK", 45, 3,
new int[] { 1958 }, new string[] { "Ferrari" })); racers.Add(new Racer("Phil", "Hill", "USA", 48, 3,
new int[] { 1961 }, new string[] { "Ferrari" })); racers.Add(new Racer("John", "Surtees", "UK", 111, 6,
new int[] { 1964 }, new string[] { "Ferrari" })); racers.Add(new Racer("Jim", "Clark", "UK", 72, 25,
new int[] { 1963, 1965 }, new string[] { "Lotus" })); racers.Add(new Racer("Jack", "Brabham", "Australia", 125, 14,
new int[] { 1959, 1960, 1966 }, new string[] { "Cooper", "Brabham" })); racers.Add(new Racer("Denny", "Hulme", "New Zealand", 112, 8,
new int[] { 1967 }, new string[] { "Brabham" })); } return racers; } private static List<Team> teams; //返回一組冠軍車隊 public static IList<Team> GetContructorChampions() { if (teams == null) { teams = new List<Team>() { new Team("Vanwall", 1958), new Team("Cooper", 1959, 1960), new Team("Ferrari", 1961, 1964, 1975, 1976, 1977, 1979, 1982, 1983, 1999,
2000, 2001, 2002, 2003, 2004, 2007, 2008), new Team("BRM", 1962), new Team("Lotus", 1963, 1965, 1968, 1970, 1972, 1973, 1978), new Team("Brabham", 1966, 1967), new Team("Matra", 1969), new Team("Tyrrell", 1971), new Team("McLaren", 1974, 1984, 1985, 1988, 1989, 1990, 1991, 1998), new Team("Williams", 1980, 1981, 1986, 1987, 1992, 1993, 1994, 1996, 1997), new Team("Benetton", 1995), new Team("Renault", 2005, 2006 ), new Team("Brawn GP", 2009), new Team("Red Bull Racing", 2010, 2011) }; } return teams; } private static List<Championship> championships; //返回GetChampionships類型的集合 public static IEnumerable<Championship> GetChampionships() { if (championships == null) { championships = new List<Championship>(); championships.Add(new Championship { Year = 1950, First = "Nino Farina", Second = "Juan Manuel Fangio", Third = "Luigi Fagioli" }); championships.Add(new Championship { Year = 1951, First = "Juan Manuel Fangio", Second = "Alberto Ascari", Third = "Froilan Gonzalez" }); championships.Add(new Championship { Year = 1952, First = "Alberto Ascari", Second = "Nino Farina", Third = "Piero Taruffi" }); championships.Add(new Championship { Year = 1953, First = "Alberto Ascari", Second = "Juan Manuel Fangio", Third = "Nino Farina" }); championships.Add(new Championship { Year = 1954, First = "Juan Manuel Fangio", Second = "Froilan Gonzalez", Third = "Mike Hawthorn" }); championships.Add(new Championship { Year = 1955, First = "Juan Manuel Fangio", Second = "Stirling Moss", Third = "Eugenio Castellotti" }); championships.Add(new Championship { Year = 1956, First = "Juan Manuel Fangio", Second = "Stirling Moss", Third = "Peter Collins" }); } return championships; } }
//車手類 [Serializable] public class Racer : IComparable<Racer>, IFormattable { public Racer(string firstName, string lastName, string country, int starts, int wins) : this(firstName, lastName, country, starts, wins, null, null) { } public Racer(string firstName, string lastName, string country, int starts,
int wins, IEnumerable<int> years, IEnumerable<string> cars) { this.FirstName = firstName; this.LastName = lastName; this.Country = country; this.Starts = starts; this.Wins = wins; this.Years = new List<int>(years); this.Cars = new List<string>(cars); } //單值屬性 public string FirstName { get; set; } public string LastName { get; set; } public string Country { get; set; } public int Wins { get; set; } public int Starts { get; set; } //多值屬性,車手可能多次獲得冠軍,所在的車隊也可能不同 public IEnumerable<string> Cars { get; private set; } public IEnumerable<int> Years { get; private set; } public override string ToString() { return String.Format("{0} {1}", FirstName, LastName); } public int CompareTo(Racer other) { if (other == null) return -1; return string.Compare(this.LastName, other.LastName); } public string ToString(string format) { return ToString(format, null); } public string ToString(string format, IFormatProvider formatProvider) { switch (format) { case null: case "N": return ToString(); case "F": return FirstName; case "L": return LastName; case "C": return Country; case "S": return Starts.ToString(); case "W": return Wins.ToString(); case "A": return String.Format("{0} {1}, {2}; starts: {3}, wins: {4}", FirstName, LastName, Country, Starts, Wins); default: throw new FormatException(String.Format("Format {0} not supported", format)); } } }
//獲得冠軍的車隊 [Serializable] public class Team { public Team(string name, params int[] years) { this.Name = name; this.Years = new List<int>(years); } public string Name { get; private set; } public IEnumerable<int> Years { get; private set; } } //獲獎選手和年份 public class Championship { public int Year { get; set; } public string First { get; set; } public string Second { get; set; } public string Third { get; set; } }