1.List<> 常見操作
1.數據
IEnumerable<string> lstNew = null; List<string> lstOne = new List<string>(){"January", "February", "March"}; List<string> lstTwo = new List<string>() { "January", "April", "March"}; List<string> lstThree = new List<string>() { "January", "April", "March", "May" }; List<string> lstFour = new List<string>() { "Jan", "Feb", "Jan", "April", "Feb" };
2.輸入
static void PrintList(IEnumerable<string> str) { foreach (var s in str) Console.WriteLine(s); Console.WriteLine("-------------"); }
3.常用操作(命名空間:System.Linq)
Enumberable.Intersect(); // Compare two List<string> and display common elements lstNew = lstOne.Intersect(lstTwo, StringComparer.OrdinalIgnoreCase); PrintList(lstNew);
輸出相同元素:JANUARY MARCH
Enumerable.Except // Compare two List<string> and display items of lstOne not in lstTwo lstNew = lstOne.Except(lstTwo, StringComparer.OrdinalIgnoreCase); PrintList(lstNew); Enumerable.Distinct // Unique List<string> lstNew = lstFour.Distinct(StringComparer.OrdinalIgnoreCase); PrintList(lstNew) List.ConvertAll // Convert elements of List<string> to Upper Case lstNew = lstOne.ConvertAll(x => x.ToUpper()); PrintList(lstNew); Enumerable.Concat // Concatenate and Sort two List<string> lstNew = lstOne.Concat(lstTwo).OrderBy(s => s); PrintList(lstNew); Enumerable.Concat and Enumerable.Distinct // Concatenate Unique Elements of two List<string> lstNew = lstOne.Concat(lstTwo).Distinct(); PrintList(lstNew); List.Reverse // Reverse a List<string> lstOne.Reverse(); PrintList(lstOne); List.RemoveAll // Search a List<string> and Remove the Search Item // from the List<string> int cnt = lstFour.RemoveAll(x => x.Contains("Feb")); Console.WriteLine("{0} items removed", cnt); PrintList(lstFour); Enumerable.OrderBy and Enumerable.ThenByDescending // Order by Length then by words (descending) lstNew = lstThree.OrderBy(x => x.Length) .ThenByDescending(x => x); PrintList(lstNew); Use the Enumerable.Aggregate method C# // Create a string by combining all words of a List<string> // Use StringBuilder if you want performance string delim = ","; var str = lstOne.Aggregate((x, y) => x + delim + y); Console.WriteLine(str); Console.WriteLine("-------------"); Split the string and use the Enumerable.ToList method C# // Create a List<string> from a Delimited string string s = "January February March"; char separator = ' '; lstNew = s.Split(separator).ToList(); PrintList(lstNew); Use the List(T).ConvertAll method C# // Convert a List<int> to List<string> List<int> lstNum = new List<int>(new int[] { 3, 6, 7, 9 }); lstNew = lstNum.ConvertAll<string>(delegate(int i) { return i.ToString(); }); PrintList(lstNew); Use Enumerable.GroupBy, Enumerable.Select and Enumerable.OrderByDescending // Count Repeated Words var q = lstFour.GroupBy(x => x) .Select(g => new { Value = g.Key, Count = g.Count() }) .OrderByDescending(x => x.Count); foreach (var x in q) { Console.WriteLine("Value: " + x.Value + " Count: " + x.Count); }
關於排序
1.排序1
multiSpecialRoute[0].Sort(delegate(CorpFlightSearchFlightEntity x, CorpFlightSearchFlightEntity y) { return x.PrintPrice.CompareTo(y.PrintPrice); });
2.排序2
this._appFlightsList.Sort(AppFlightSorter.CorpSort); public static int CorpSort(FlightOnlineAppEntity Entity1, FlightOnlineAppEntity Entity2) { //起飛時間對比 int Result = Entity1.DepartTime.CompareTo(Entity2.DepartTime); //如果兩者的起飛時間不同,按起飛時間排序 if (Result != 0) { return Result; } //如果兩者的起飛時間相同,再按價格排序 else { Result = Entity1.Flight.Trim().ToUpper().CompareTo(Entity2.Flight.Trim().ToUpper()); if (Result != 0) { return Result; } else { return Entity1.Price.CompareTo(Entity2.Price); } } }
3.移除
this._appFlightsList.RemoveAll(FirstSingleFlightFinder.IsFirstSingleFlight); public static bool IsFirstSingleFlight(FlightOnlineAppEntity flight) { if (flight.PriceType.Trim().ToUpper() != "SINGLETRIPPRICE") { return false; } if (flight.Class.Trim().ToUpper() != "F") { return false; } return true; }
4.for循環
一般你會想到for(int i=0;i<count;i++){}這種寫法,還可能想到foreach(var item in collection)這種寫法,但是下面的寫法比較簡潔了。
this._appFlightsList.ForEach(ShowFlightsUICommon.SetAppFlight); public static void SetAppFlight(FlightOnlineAppEntity flight) { flight.HasTicketLimit = !string.IsNullOrEmpty(flight.TicketLimit); flight.HasRecommend = !string.IsNullOrEmpty(flight.RecommendString); }
還有更加簡潔的寫法就是用代理,如下,注意這個方法沒有返回值,不能寫成
List<ChoiceItem> items = row.ChoiceItems.ForEach(delegate(ChoiceItem item) { item.ItemContent = item.Option + "." + item.ItemContent; });
CheckBoxList chklist = e.Item.FindControl("chklist") as CheckBoxList; chklist.Visible = true; List<ChoiceItem> items = row.ChoiceItems; items.ForEach(delegate(ChoiceItem item) { item.ItemContent = item.Option + "." + item.ItemContent; }); chklist.DataSource = items; chklist.DataTextField = "ItemContent"; chklist.DataValueField = "Option"; chklist.DataBind();
5.查找,注意只要list不為空,無論他的查找是否符合條件,返回結果都不為空,這一點很省心。
如果僅僅List<student> list;編譯不通過:使用了未賦值的變量list。
如果僅僅List<student> list = null;這樣編譯不報錯,運行的時候報錯:未將對象引用設置到對象實例。
所以只要List<student> list = new List<student>();可保正常運行。
public class student { private int _id; private string _name; public student(int id, string name) { this._id = id; this._name = name; } public int ID { get { return _id; } set { _id = value; } } public string Name { get { return _name; } set { _name = value; } } } protected void Button1_Click(object sender, EventArgs e) { List<student> list = new List<student>(); list.Add(new student(1, "a")); list.Add(new student(2, "b")); list.Add(new student(3, "c")); list.Add(new student(4, "d")); List<student> curr = list.FindAll(delegate(student s) { return s.ID == 6; }); foreach (student item in curr) { Response.Write("ID:" + item.ID + " Name:" + item.Name + "\r\n"); } }
還有一種簡便的寫法
List<RecipientEntity> recipient8 = tempConfirmRecList.FindAll(delegate(RecipientEntity re) { return re.MailType == 8; }); List<RecipientEntity> recipient8 = tempConfirmRecList.FindAll(re => re.MailType == 8); 注意括號里面沒有;
2.IQueryable, IEnumerable, IList的區別
TestIQueryable private static void TestIQueryable() { using (var ctx = new WrappedNorthWindEntities()) { IQueryable<Product> expression = ctx.Products.Take(5); IQueryable<Product> products = expression.Take(2); // A 不執行SQL Console.WriteLine(products.Count()); // B SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )) Console.WriteLine(products.Count()); // C SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )) foreach (Product p in products) // D SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] { Console.WriteLine(p.ProductName); } foreach (Product p in products) // E SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ) { Console.WriteLine(p.ProductName); } } }
TestIEnumerable private static void TestIEnumerable() { using (var ctx = new WrappedNorthWindEntities()) { IEnumerable<Product> expression = ctx.Products.Take(5).AsEnumerable(); IEnumerable<Product> products = expression.Take(2); // A 不執行SQL Console.WriteLine(products.Count()); // B SELECT TOP (5) * FROM [dbo].[Products] Console.WriteLine(products.Count()); // C SELECT TOP (5) * FROM [dbo].[Products] foreach (Product p in products) // D SELECT TOP (5) * FROM [dbo].[Products] { Console.WriteLine(p.ProductName); } foreach (Product p in products) // E SELECT TOP (5) * FROM [dbo].[Products] { Console.WriteLine(p.ProductName); } } }
TestIList private static void TestIList() { using (var ctx = new WrappedNorthWindEntities()) { var expression = ctx.Products.Take(5); IList<Product> products = expression.Take(2).ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] Console.WriteLine(products.Count()); // B 不執行SQL Console.WriteLine(products.Count()); // C 不執行SQL foreach (Product p in products) // D 不執行SQL { Console.WriteLine(p.ProductName); } foreach (Product p in products) // E 不執行SQL { Console.WriteLine(p.ProductName); } } }
- IQueryable和IEnumerable都是延時執行(Deferred Execution)的,而IList是即時執行(Eager Execution)
- IQueryable和IEnumerable在每次執行時都必須連接數據庫讀取,而IList讀取一次后,以后各次都不需連接數據庫。前兩者很容易造成重復讀取,性能低下,並且可能引發數據不一致性
- IQueryable和IEnumerable的區別:IEnumberalb使用的是LINQ to Object方式,它會將AsEnumerable()時對應的所有記錄都先加載到內存,然后在此基礎上再執行后來的Query。所以上述TestIEnumerable例子中執行的SQL是"select top(5) ...",然后在內存中選擇前兩條記錄返回。
以下是一個IQueryable引發數據不一致性的例子:記錄總數和記錄詳情兩者本應一致,但由於IQueryable前后兩次讀取數據庫,結果是現實有10條記錄,卻輸出11條詳情。
IQueryable Data Inconsistancy IQueryable<Product> products = ctx.Products.All(); //開始的時候數據庫product表中有10條記錄, count = 10 int count = products.Count(); Console.WriteLine("Count of products:"+count); //此時另一進程添加一個產品進數據庫 //會重新讀取數據庫並輸出11個產品名稱 foreach (Product p in products) { Console.WriteLine(p.ProductName); }
基於性能和數據一致性這兩點,我們使用IQueryable時必須謹慎,而在大多數情況下我們應使用IList。
1.當你打算馬上使用查詢后的結果(比如循環作邏輯處理或者填充到一個table/grid中),並且你不介意該查詢會即時執行,使用ToList()
2.當你希望查詢后的結果可以供調用者(Consummer)作后續查詢(比如這是一個"GetAll"的方法),或者你希望該查詢延時執行,使用AsQueryable()
3.Linq操作
1.where過濾查詢
使用where篩選在倫敦的客戶
var q = from c in db.Customers where c.City == "London" select c;
再如:篩選1994 年或之后雇用的雇員:
var q = from e in db.Employees where e.HireDate >= new DateTime(1994, 1, 1) select e;
篩選庫存量在訂貨點水平之下但未斷貨的產品:
var q = from p in db.Products where p.UnitsInStock <= p.ReorderLevel && !p.Discontinued select p;
篩選出UnitPrice 大於10 或已停產的產品:
var q = from p in db.Products where p.UnitPrice > 10m || p.Discontinued select p;
調用兩次where以篩選出UnitPrice大於10且已停產的產品:
var q = db.Products.Where(p=>p.UnitPrice > 10m).Where(p=>p.Discontinued);
返回集合中的一個元素,其實質就是在SQL語句中加TOP (1)
選擇表中的第一個發貨方
Shipper shipper = db.Shippers.First();
選擇CustomerID 為“BONAP”的單個客戶
Customer cust = db.Customers.First(c => c.CustomerID == "BONAP");
選擇運費大於 10.00 的訂單:
Order ord = db.Orders.First(o => o.Freight > 10.00M);
2.select,distinct
返回僅含客戶聯系人姓名的序列
var q = from c in db.Customers select c.ContactName;
這個語句只是一個聲明或者一個描述,並沒有真正把數據取出來,只有當你需要該數據的時候,它才會執行這個語句,這就是延遲加載(deferred loading)。如果,在聲明的時候就返回的結果集是對象的集合。可以使用ToList() 或ToArray()方法把查詢結果先進行保存,然后再對這個集合進行查詢。當然延遲加載(deferred loading)可以像拼接SQL語句那樣拼接查詢語法,再執行它。
說明:匿名類型是C#3.0中新特性。其實質是編譯器根據我們自定義自動產生一個匿名的類來幫助我們實現臨時變量的儲存。匿名類型還依賴於另外一個 特性:支持根據property來創建對象。比如,var d = new { Name = "s" };編譯器自動產生一個有property叫做Name的匿名類,然后按這個類型分配內存,並初始化對象。但是var d = new {"s"};是編譯不通過的。因為,編譯器不知道匿名類中的property的名字。例如string c = "d";var d = new { c}; 則是可以通過編譯的。編譯器會創建一個叫做匿名類帶有叫c的property。
例如下 例:new{c,ContactName,c.Phone};ContactName和Phone都是在映射文件中定義與表中字段相對應的 property。編譯器讀取數據並創建對象時,會創建一個匿名類,這個類有兩個屬性,為ContactName和Phone,然后根據數據初始化對象。 另外編譯器還可以重命名property的名字。
使用 SELECT 和匿名類型返回僅含客戶聯系人姓名和電話號碼的序列
var q = from c in db.Customers select new {c.ContactName, c.Phone};
使用SELECT和匿名類型返回僅含雇員姓名和電話號碼的序列,並將FirstName和LastName字段合並為一個字段“Name”,此外在所得的序列中將HomePhone字段重命名為Phone。
var q = from e in db.Employees select new { Name = e.FirstName + " " + e.LastName, Phone = e.HomePhone };
使用SELECT和匿名類型返回所有產品的ID以及HalfPrice(設置為產品單價除以2所得的值)的序列。
var q = from p in db.Products select new { p.ProductID, HalfPrice = p.UnitPrice / 2 };
使用SELECT和條件語句返回產品名稱和產品供貨狀態的序列
var q = from p in db.Products select new { p.ProductName, Availability = p.UnitsInStock - p.UnitsOnOrder < 0 ? "Out Of Stock" : "In Stock" };
返回你自定義類型的對象集,使用SELECT和已知類型返回雇員姓名的序列
var q = from e in db.Employees select new Name { FirstName = e.FirstName, LastName = e.LastName };
結合where使用,起到過濾作用,使用SELECT和WHERE返回僅含倫敦客戶聯系人姓名的序列
var q = from c in db.Customers where c.City == "London" select c.ContactName;
select操作使用了匿名對象,而這個匿名對象中,其屬性也是個匿名對象,使用SELECT 和匿名類型返回有關客戶的數據的整形子集。查詢顧客的ID和公司信息(公司名稱,城市,國家)以及聯系信息(聯系人和職位)
var q = from c in db.Customers select new { c.CustomerID, CompanyInfo = new {c.CompanyName, c.City, c.Country}, ContactInfo = new {c.ContactName, c.ContactTitle} };
返回的對象集中的每個對象DiscountedProducts屬性中,又包含一個集合。也就是每個對象也是一個集合類,使用嵌套查詢返回所有訂單及其OrderID 的序列、打折訂單中項目的子序列以及免送貨所省下的金額
var q = from o in db.Orders select new { o.OrderID, DiscountedProducts = from od in o.OrderDetails where od.Discount > 0.0 select od, FreeShippingDiscount = o.Freight };
查詢中調用本地方法PhoneNumberConverter將電話號碼轉換為國際格式
var q = from c in db.Customers where c.Country == "UK" || c.Country == "USA" select new { c.CustomerID, c.CompanyName, Phone = c.Phone, InternationalPhone = PhoneNumberConverter(c.Country, c.Phone) };
PhoneNumberConverter方法如下:
public string PhoneNumberConverter(string Country, string Phone) { Phone = Phone.Replace(" ", "").Replace(")", ")-"); switch (Country) { case "USA": return "1-" + Phone; case "UK": return "44-" + Phone; default: return Phone; } }
下面也是使用了這個方法將電話號碼轉換為國際格式並創建XDocument
XDocument doc = new XDocument( new XElement("Customers", from c in db.Customers where c.Country == "UK" || c.Country == "USA" select (new XElement("Customer", new XAttribute("CustomerID", c.CustomerID), new XAttribute("CompanyName", c.CompanyName), new XAttribute("InterationalPhone", PhoneNumberConverter(c.Country, c.Phone)) ))));
篩選字段中不相同的值。用於查詢不重復的結果集。生成SQL語句為:SELECT DISTINCT [City] FROM [Customers],查詢顧客覆蓋的國家
var q = ( from c in db.Customers select c.City ) .Distinct();