19.1 LINQ provider
LINQ數據源能夠是SQL數據庫、數組、XML文檔,每一種數據源類型,都有根據該數據源實現查詢的代碼模塊,叫作LINQ provider。有LINQ to objects、LINQ to xml、LINQ to SQL、LINQ to Datasets、LINQ to Entities。
//一個簡單的LINQ例子
int[] nums = { 2,13,4,15};//數據源
IEnumerable<int> lowNums = from n in nums where n < 10 select n;//定義並存儲查詢返回一個枚舉類
foreach (var x in lowNums)
{
Console.WriteLine("{0},", x);
}
19.2 匿名類型
匿名類型的對象建立表達式:
匿名類型沒有名字,必須使用var關鍵字來做爲變量類型
//匿名類型
var student = new { Name = "Mary Jones", Age = 19, Major = "History" };//必須使用var {}內爲匿名對象初始化語句
Console.WriteLine("{0},{1},{2}",student.Name,student.Age,student.Major);
string major = "History";
var student1 = new { Other.name, Age = 19, major };//分別是賦值形式成員訪問表達式形式和標識符形式
Console.WriteLine("{0},{1},{2}", student.Name, student.Age, student.Major);
19.2 方法語法和查詢表達式
在寫LINQ查詢的實收可使用兩種形式的語法:查詢和方法
//方法語法與查詢語法
int[] nums1 = { 2, 5, 26, 62, 45, 77, 74 };
var numsQuery = from n in nums1 where n < 20 select n;//查詢語法
var numsMethod = nums1.Where(x => x < 20);//方法語法
int numsCount=(from n in nums1 where n<20 select n).Count();//兩種形式的組合
19.3 查詢變量
查詢變量就是LINQ查詢返回的值,有枚舉類的IEnumerable<T>和標量int。
若是查詢表達式返回枚舉,查詢一直處處理枚舉時才執行,而若是返回標量,則當即執行,並把結果保存在查詢變量中。
19.4 查詢表達式的結構
順序:from……select……這兩部分是必需的;select子句在最後面
from子句
join子句
var query=from s in a join c in b on a.ID= equals b.ID
let子句
where子句
例子
var groupA=new[]{3,4,5,6};
var groupB=new[]{6,7,8,9};
var someInts = fromint a in groupA//必需的第一個from子句
fromint b in groupB//第二個from子句
let sum = a + b//let子句在新的變量中保存結果
where sum >= 11 //where條件1
where a == 4//where條件2
selectnew { a, b, sum };
orderby子句
查詢中的匿名類型
var students = new[]{
new {LName="Jones",FName="Mary",Age=19,Major="History"},
new {LName="Smith",FName="Bob",Age=20,Major="CompSci"},
new {LName="Fleming",FName="Carol",Age=21,Major="Math"}
};//定義一個匿名類型的對象數組每一個匿名類型的對應屬性名字必需相同
var query = from s in students selectnew { s.LName, s.FName, s.Major };
//在select子句中建立一個匿名類型
group by子句
var query = from s in students
group s by s.Major;
foreach (var s in query)
{
Console.WriteLine("{0}",s.Key);//分組鍵
foreach(var t in s)
{ Console.WriteLine(" {0},{1}", t.LName, t.FName); }
}
into子句
var groupA=new[]{3,4,5,6};
var groupB=new[]{6,7,8,9};
var someInts1 = fromint a in groupA
join b in groupB on a equals b
into groupAB//將前面的查詢結果插入到新的groupAB中
from c in groupAB
select c;
19.5 標準查詢運算符
標準運算符就是一系列的API方法,可以查詢任何.NET數組和集合。
對於標準查詢運算符,被查詢的集合對象叫作序列。
序列:它必須實現IEnumerable<T>接口,包括List<>、Dictionary<>、Stack<>、Array等。
標準查詢運算符:Where Select SelectMane Take Skip TakeWhile SkipWhile Join GroupJoin Concat ……Count Sum Contains All Any Max Last First Range FirstOrDefalut…
19.6.1標準查詢運算符的簽名
System.Linq.Enumerable類聲明瞭標準查詢運算符方法,這些方法不單單是一些方法,它們是擴展了IEnumerable<T>泛型類的擴展方法,IEnumerable<T>就是實現了接口IEnumerable的全部類類型。例子以下:
int[] array = newint[] { 3,4,5,6,7,9};
var c1 = Enumerable.Count(array);
var f1 = Enumerable.First(array);//方法語法
var c2 = array.Count();
//擴展語法 int數組繼承自Array類 該類實現了IENumerable<T>接口 因此能夠是被擴展對象
var f2 = array.First();
Count方法簽名
publicstaticint Count<TSource>(thisIEnumerable<TSource> source);
擴展方法是公共的靜態方法,儘管定義在一個類中,但目的是爲了另外一個類(第一個形參)增長功能,因此叫擴展方法。
19.6.2 將委託做爲參數
委託能夠理解爲:一個包含特殊簽名和返回類型的方法或方法列表的對象,當委託被調用時,包含它的方法會被依次調用。
Count方法還有一種重載形式:
public static int Count<TSource>(thisIEnumerable<TSource> source, Func<TSource, bool> predicate);
其中第二個參數就是泛型委託參數。Func<TSource, bool> predicate:接受單個T類型的參數做爲方法參數而且返回一個bool類型的值。這種委託成爲謂詞。
LINQ預約義委託:Func委託和Action委託,各有17個成員。咱們用做實參的委託對象必須是這些類型之一。Fuc委託有返回類型,而Action沒有。
Func委託:
委託的幾種定義方式:方法、匿名方法、Lambda表達式
Func<string, string, string> func1 = Hello;
// Func委託,是微軟爲咱們預約義的經常使用委託前面的T參數都表示的是方法的輸入參數最後一個TResult參數是方法返回結果參數
Func<string, string, string> func2 = delegate(string a, string b) { return"func2" + Environment.NewLine + a + " " + b; };
//匿名方法 delegate+(參數列表)+{方法體}
Func<string, string, string> func3 = (a, b) => { return"func3" + Environment.NewLine + a + " " + b; };
//Lambda表達式 (,,) => { } 左邊爲參數列表右邊爲表達式體
匿名對象
var person = new { name = "yuanxiaoxia", age = 27 };//定義了一個匿名對象person,有兩個屬性string和int類型
例子:--使用委託對象來調用標準查詢運算符方法Count
static bool IsOdd(int x)
{
return x % 2 == 1;
}
static void Main()
{
int[] array = new int[] { 3, 4, 5, 6, 7, 9 };
Func<int, bool> myDel = newFunc<int, bool>(IsOdd);
var countOdd = array.Count(myDel);
var countOdd1 = Enumerable.Count(array,myDel);//兩種調用委託的方式
}
燕青解答:
Count是一個擴展方法,是IEnumerable<TSourse>泛型的一個擴展方法,它接受一個委託類型的參數:Func<Tsource,bool>
Lambda表達式就是一個方法的簡寫
委託是一個數據類型,實例化一個委託對象時 把具備委託定義的方法簽名的方法 作爲參數傳入,因此這個方法能夠是任何形式,能夠傳入一個Lambda表達式也能夠是一個普通的方法,或是匿名方法
還可使用更簡潔的方法,Lambda表達式來做爲參數
例子:--使用Lambda表達式來調用標準查詢運算符方法Count
var countOdd2 = array.Count(x => x % 2 == 1);
也可使用匿名方法
例子:--使用匿名方法來調用標準查詢運算符方法Count
Func<int, bool> Del = delegate(int x) { return x % 2 == 1; };//匿名方法:delegate+(參數列表)+{方法體}
var countOdd3 = array.Count(Del);
19.6 LINQ to XML
LINQ與xml能夠經過兩種方式配合使用:第一種是xml操做API;第二種是使用LINQ查詢工具
19.6.1 API:
1、建立、保存、加載和顯示xml文檔
XDocument employees1 = newXDocument(newXElement("Employees",newXElement("Name","Bob"),newXElement("NAme","Sally")));
employees1.Save("EmployeesFile.xml");
XDocument employees2 = XDocument.Load("EmployeesFile.xml");
Console.WriteLine(employees2);
2、獲取xml樹的值
XDocument employeeDoc = newXDocument(
newXElement("Employees", newXElement("Employee", newXElement("Name", "Bob"), newXElement("PhoneNum", "13468654108")),
newXElement("Employee",newXElement("Name","Sally"),newXElement("PhoneNum","13468654102"),newXElement("PhoneNum","13468654101"))));
XElement root = employeeDoc.Element("Employees");
IEnumerable<XElement> employees=root.Elements();
foreach (XElement emp in employees)
{
XElement empNameNode = emp.Element("Name");
Console.WriteLine(empNameNode.Value);
IEnumerable<XElement> empPhones = emp.Elements("PhoneNum");
foreach (XElement empPhone in empPhones)
{
Console.WriteLine(" {0}", empPhone.Value);
}
}
![](http://static.javashuo.com/static/loading.gif)
3、增長節點以及操做xml
XDocument xd = newXDocument(
newXElement("root", newXElement("first"))
);
Console.WriteLine("Original tree");
Console.WriteLine(xd);
XElement rt = xd.Element("root");
rt.Add(newXElement("Second"));
rt.Add(newXElement("Third"), newXComment("Important Comment"), newXElement("Fourth"));
Console.WriteLine("Modified tree");
Console.WriteLine(xd);
![](http://static.javashuo.com/static/loading.gif)
4、xml特性(XAttribute)
XDocument xd = newXDocument(
newXElement("root",
newXAttribute("color","red"),//特性構造函數,接受兩個參數name和value
newXAttribute("size","large"),
newXElement("first"),
newXElement("Second"))
); //建立xml樹
Console.WriteLine(xd);
XElement rt = xd.Element("root");//獲取元素
XAttribute color = rt.Attribute("color");//獲取節點特性
Console.WriteLine("color is {0}",color.Value);//讀取特性的value值
rt.Attribute("color").Remove();//移除節點的一個color特性
rt.SetAttributeValue("size", null);//size特性賦值爲空,其實也就是移除節點的一個size特性
rt.SetAttributeValue("size", "medium");//改變特性值
rt.SetAttributeValue("width", "narrow");//添加特性width
Console.WriteLine(xd);
5、節點的其餘類型
(1)XComment 註釋 <!--內容-->
(2)XDeclaration xml聲明
(3)XProcessingInstruction
XDocument xd = newXDocument(
newXDeclaration("1.0", "utf-8", "yes"),
newXDocument("This is a comment"),
newXProcessingInstruction("xml-stylesheet", @"href=""stories.css"" type=""test/css"""),
newXElement("root",
newXElement("first"),
newXElement("Second")
)
);
結果:
19.6.2 LINQ查詢
使用LINQ查詢來獲得節點的子集
XDocument xd = newXDocument(
newXElement("MyElements",
newXElement("first",
newXAttribute("color", "red"),
newXAttribute("size", "small")),
newXElement("second",
newXAttribute("color", "red"),
newXAttribute("size", "medium")),
newXElement("third",
newXAttribute("color", "blue"),
newXAttribute("size", "large")))
);
Console.WriteLine(xd);
xd.Save("SimpleSample.xml");
xd = XDocument.Load("SimpleSample.xml");//加載文檔
XElement rt = xd.Element("MyElements");//獲取根元素
var xyz = from e in rt.Elements()
where e.Name.ToString().Length == 5
select e;//選擇名稱包含5個字符的元素
foreach (XElement x in xyz)
Console.WriteLine(x.Name.ToString());//所選的元素
Console.WriteLine();
foreach (XElement x in xyz)
Console.WriteLine("Name:{0},color:{1},size:{2}",x.Name,x.Attribute("color").Value,x.Attribute("size").Value);
var xyz1 = from e in rt.Elements()
selectnew { e.Name,color=e.Attribute("color")};//建立匿名類型
foreach (var x in xyz1)
Console.WriteLine(x);
結果: