LINQ 查询

var query = from r in Formula1.GetChampions()
where r.Country == "Brazil"
orderby r.Wins descending
select r; foreach (Racer racer in query)
{
Console.WriteLine("{0:A}", racer);
}

扩展方法

LINQ为IEnumerable<T>接口提供各种扩展方法,以便用户实现了该接口的任意集合上使用LINQ查询。扩展方法在静态类中声明,定义一个静态方法,第一参数定义扩展的类型。

扩展方法可以将方法写入最初没有提供该方法的类中,可以把方法添加到实现某个特定接口的任何类中,这样多个类可以使用相同的实现代码。

class Program
{
private static void Main(string[] args)
{
string s1 = "";
s1.Function(); string s2 = "";
s2.Function();
}
} public static class StringExtension
{
public static void Function(this string s)
{
Console.WriteLine("this string is " + s);
}
}

第一个参数 this 用来区分是扩展方法还是静态方法。

第二个参数 需要对应扩展的类。

注意 扩展方法里不能访问类型的私有成员。

还可以这样调用

StringExtension.Function(s1);

LINQ 扩展示例

var champions = new List<Racer>(Formula1.GetChampions());
IEnumerable<Racer> brazilChampions =
champions.Where(r => r.Country == "Brazil").
OrderByDescending(r => r.Wins).
Select(r => r); foreach (Racer r in brazilChampions)
{
Console.WriteLine("{0:A}", r);
}

推迟查询的执行

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);
}

namesWithJ 一旦使用了ToArray、ToList之类的。就 names 了。如

var namesWithJ = (from n in names
where n.StartsWith("J")
orderby n
select n).ToList();

标准的查询操作

Enumberable 类定义的标准查询操作符。

标准查询操作符

说明

Where

OfType<TResult>

称为筛选操作符定义返回元素的条件。

Where     使用谓词,返回符合条件的元素。

OfType<TResult>  返回符合类型的元素。

Select

SelectMany

投射操作符用于把对象转换为另一个类型的新对象。

Select 和 SelectMany 定义根据选择器函数选择结果值的投射。

OrderBy

ThenBy

OrderByDescending

ThenByDescending

Reverse

排序操作符改变返回的元素的顺序。

Orderby 升序排序。

OrderBydescending  降序排序。

TheBy 和 ThenByDescending 二次排序。

Reverse 反转集合元素。

Join

GroupJoin

连接操作符。用于合并不直接相关的集合。

Join     根据键选择器函数连接两个集合。

GroupJoin   连接两个集合。

GroupBy

ToLookup

组合操作符把数据放在组中。

GroupBy   组合公共键的元素。

Tookup    创建一个一对多字典,组合元素。

Any

All

Contains

限定操作符,元素满足指定的条件。

Any 满足谓词函数的函数。

All  所有元素是否都满足谓词函数。

Contains   检查某个元素是否在集合中。

Take

Skip

TakeWhile

SkipWhile

分区操作符返回集合的子集。

Take 从集合提取元素个数。

Skip 跳过指定的元素个数,提取其他元素。

TakeWhile 提取条件为真的元素。

Distinct

Union

Intersect

Except

Zip

Set操作符返回一个集合。

Distinct 删除重复的元素。

Union 返回集合中唯一元素。

Intersect  返回两个集合都有的元素。

Except  只出现在一个集合中的元素。

Zip 两个集合合并为一个元素。

First

FirstOrDefault

Last

LastOrDefault

ElementAt

ElementAtOrDefault

Single

SingleOrDefault

元素操作符返回一个元素。

First                 返回第一个满足条件的元素。

FirstOrDefault  类似First,如果未找到满足条件元素,返回类型的默认值。

Last                 返回最后一个满足条件的元素。

ElementAt        返回元素的位置。

Single               返回一个满足条件的元素。如果有多个元素都满足条件,就抛出一个异常。

Count

Sum

Min

Max

Average

Aggregate

聚合操作符计算集合值。

Sum 总和。

Count  所有元素个数。

Min  最小元素。

Max  最大元素。

Average 平均值。

Aggregate  根据输入的表达式获取聚合值。

ToArray

AsEnumerable

ToList

ToDictionary

Cast<TResult>

转换操作符。

Empty

Range

Repeat

生成操作符。

Empty 空集合。

Range 返回一系列数字。

Repeat 返回始终重复一直的集合。

筛选

where子句合并多个表达式。

 var racers = from r in Formula1.GetChampions()
where r.Wins > && (r.Country == "Brazil" || r.Country == "Austria")
select r; foreach (var racer in racers)
{
Console.WriteLine("{0:A}", racer);
}

下面代码有Where扩展方法Where和Select调用。

var racers = Formula1.GetChampions().
Where(r => r.Wins > && (r.Country == "Brazil" || r.Country == "Austria")).
Select(r => r);

索引器筛选

索引是筛选器返回的每个结果的计数器。

下面由Where扩展方法调用, 使用索引返回。

var racers = Formula1.GetChampions().
Where((r, index) => r.Wins > && index % != );

类型筛选

基于类型筛选,使用 OfType 扩展方法。

 object[] data = {"one", , , "li"};
var query = data.OfType<int>(); foreach (var intValue in query)
{
Console.WriteLine("{0}", intValue);
}

复合的from子句

var ferrariDrivers = from r in Formula1.GetChampions()
from c in r.Cars
where c == "Ferrari"
orderby r.LastName
select r.FirstName + " " + r.LastName; foreach (string name in ferrariDrivers)
{
Console.WriteLine("{0}", name);
}

C#编译器把复合的from子句和LINQ查询转换为SelectMany扩展方法。SelectMany方法用于迭代序列的序列。

var ferrariDrivers = Formula1.GetChampions().
SelectMany( r => r.Cars ,
(r,c) => new { Racer = r, Car = c }).
Where(r => r.Car == "Ferrari").
OrderBy(r => r.Racer.LastName).
Select(r => r.Racer.FirstName + " " + r.Racer.LastName);

排序

对序列排序,前面使用了orderby 子句。使用两种方法。

var racers = from r in Formula1.GetChampions()
where r.Country == "Brazil"
orderby r.Wins descending
select r; var racers2 = Formula1.GetChampions().Where(r => r.Country == "Brazil").OrderByDescending(r => r.Wins).Select(r => r);

OrderBy() 和 OrderByDescending() 方法返回 IOrderEnumerable<Tsource> 这个接口派生自IEnumerable<TSource>接口,包含一个额外的方法 CreateOrderedEnumerable<TSource>()。这个方法用于进一步非序列排序。根据关键字选择器来排序,可以使用ThenBy() 和 ThenByDescending() 方法继续排序。 这两个方法 需要 IOrderEnumerable<TSource> 接口才能工作,但也返回这个接口。所以添加任意多个ThenBy() 和 ThenByDescending() 方法,对集合排序。

Linq查询时,需要把所有用于排序的不同关键字 用逗号 分割开。 添加到 orderby 子句。 扩展方法 Take  提取前面 10 个元素。

var racers = (from r in Formula1.GetChampions()
orderby r.Country, r.LastName, r.FirstName
select r).Take();
foreach (var item in racers)
{
Console.WriteLine(item);
}

也可以使用 OrderBy() 和 ThenBy() 扩展方法执行相同的操作:

var racers = (from r in Formula1.GetChampions()
orderby r.Country, r.LastName, r.FirstName
select r).Take();
foreach (var item in racers)
{
Console.WriteLine(item);
} Console.WriteLine("***********"); var racers2 = Formula1.GetChampions().
OrderBy(r => r.Country).
ThenBy(r => r.LastName).
ThenBy(r => r.FirstName).
Take(); foreach (var item in racers2)
{
Console.WriteLine(item);
}

分组

根据一个关键字值对查询结果进行分组,使用 group 子句。

子句 group r by r.Country into g 根据 Country 属性组合。并定义一个新的标识符g。它以后用于访问分组的结果信息。

var countries = from r in Formula1.GetChampions()
group r by r.Country
into g
orderby g.Count() descending, g.Key
where g.Count() >=
select new
{
Country = g.Key,
Count = g.Count()
}; foreach (var country in countries)
{
Console.WriteLine(format: "{0,-10} {1}", arg0: country.Country, arg1: country.Count);
}

使用扩展方法,子句 group r by r.Country into g 解析为 GroupBy(r => r.Country) 返回分组序列。

var contries2 = Formula1.GetChampions().
GroupBy(r => r.Country).
OrderByDescending(g => g.Count()).
ThenBy(g => g.Key).
Where(g => g.Count() >= ).
Select(g => new
{
Country = g.Key,
Count = g.Count()
});

对嵌套的对象分组

分组的对象包含嵌套的序列,可以改变 select 子句创建的匿名类型。

var countries = from r in Formula1.GetChampions()
group r by r.Country
into g
orderby g.Count() descending, g.Key
where g.Count() >=
select new
{
Country = g.Key,
Count = g.Count(),
Racers = from racer in g
orderby racer.LastName
select racer.FirstName + " " + racer.LastName
}; foreach (var country in countries)
{
Console.WriteLine(format:"{0, -10} {1}", arg0:country.Country, arg1:country.Count);
foreach (var racer in country.Racers)
{
Console.WriteLine(format:"{0}; ", arg0:racer);
}
Console.WriteLine();
}

内连接

使用 join 子句 根据特定的条件合并两个数据源,但之前要获得两个要连接的列表。

var racers = from r in Formula1.GetChampions()
from y in r.Years
select new
{
Year = y,
Name = r.FirstName + " " + r.LastName
}; var teams = from t in Formula1.GetContructorChampions()
from y in t.Years
select new
{
Year = y,
Name = t.Name
}; //var racersAndTeams =
// (from r in racers
// join t in teams on r.Year equals t.Year
// orderby t.Year
// select new
// {
// Year = r.Year,
// Champion = r.Name,
// Constructor = t.Name
// }).Take(10); var racersAndTeams =
(from r in
from r1 in Formula1.GetChampions()
from yr in r1.Years
select new
{
Year = yr,
Name = r1.FirstName + " " + r1.LastName
} join t in
from t1 in Formula1.GetContructorChampions()
from yt in t1.Years
select new
{
Year = yt,
Name = t1.Name
}
on r.Year equals t.Year orderby t.Year
select new
{
Year = r.Year,
Champion = r.Name,
Constructor = t.Name
}).Take(); Console.WriteLine("Year World Champion\t Constructor Title");
foreach (var item in racersAndTeams)
{
Console.WriteLine("{0}: {1,-20} {2}",
item.Year, item.Champion, item.Constructor);
}

左外连接

左外连接返回左边序列中的全部元素,即使它们在右边的序列中并没有匹配的元素。

左外连接用join子句和 DefaultIfEmpty 方法定义。  使用 DefaultIfEmpty 定义其右侧的默认值。

var racers = from r in Formula1.GetChampions()
from y in r.Years
select new
{
Year = y,
Name = r.FirstName + " " + r.LastName
}; var teams = from t in Formula1.GetContructorChampions()
from y in t.Years
select new
{
Year = y,
Name = t.Name
}; var racersAndTeams =
(from r in racers
join t in teams on r.Year equals t.Year into rt
from t in rt.DefaultIfEmpty()
orderby r.Year
select new
{
Year = r.Year,
Champion = r.Name,
Constructor = t == null ? "no constructor championship" : t.Name
}).Take(); Console.WriteLine("Year Champion\t\t Constructor Title");
foreach (var item in racersAndTeams)
{
Console.WriteLine("{0}: {1,-20} {2}",
item.Year, item.Champion, item.Constructor);
}

组连接

左外连接使用了组连接和 into 子句。它有一部分与组连接相同,只不过组连接不适用 DefaultIfEmpty 方法。 使用组连接时,可以连接两个独立的序列,对于其中一个序列中的某个元素,另一个序列中存在对应项列表。

var racers = Formula1.GetChampionships()
.SelectMany(cs => new List<RacerInfo>()
{
new RacerInfo {
Year = cs.Year,
Position = ,
FirstName = cs.First.FirstName(),
LastName = cs.First.LastName()
},
new RacerInfo {
Year = cs.Year,
Position = ,
FirstName = cs.Second.FirstName(),
LastName = cs.Second.LastName()
},
new RacerInfo {
Year = cs.Year,
Position = ,
FirstName = cs.Third.FirstName(),
LastName = cs.Third.LastName()
}
}); var q = (from r in Formula1.GetChampions()
join r2 in racers on
new
{
FirstName = r.FirstName,
LastName = r.LastName
}
equals
new
{
FirstName = r2.FirstName,
LastName = r2.LastName
}
into yearResults
select new
{
FirstName = r.FirstName,
LastName = r.LastName,
Wins = r.Wins,
Starts = r.Starts,
Results = yearResults
}); foreach (var r in q)
{
Console.WriteLine("{0} {1}", r.FirstName, r.LastName);
foreach (var results in r.Results)
{
Console.WriteLine("{0} {1}", results.Year, results.Position);
}
}

集合操作

扩展方法 Distinct()、 Union()、Intersect() 和 Except() 都是集合操作。

Func<string, IEnumerable<Racer>> racersByCar =
car => from r in Formula1.GetChampions()
from c in r.Cars
where c == car
orderby r.LastName
select r; Console.WriteLine("World champion with Ferrari and McLaren");
foreach (var racer in racersByCar("Ferrari").Intersect(racersByCar("McLaren")))
{
Console.WriteLine(racer);
}

集合操作通过调用实体类的 GetHashCode() 和 Equals() 方法比较对象。 对于自定义比较,可以传递实现 IEqualityComparer<T>接口的对象。

合并

Zip 方法。 .Net 4.0 新加的,用一个谓词函数把两个相关的序列合并为一个。

 var racerNames = from r in Formula1.GetChampions()
where r.Country == "Italy"
orderby r.Wins descending
select new
{
Name = r.FirstName + " " + r.LastName
}; var racerNamesAndStarts = from r in Formula1.GetChampions()
where r.Country == "Italy"
orderby r.Wins descending
select new
{
LastName = r.LastName,
Starts = r.Starts
}; var racers = racerNames.Zip(racerNamesAndStarts, (first, second) => first.Name + ", starts: " + second.Starts);
foreach (var r in racers)
{
Console.WriteLine(r);
}

分区

扩展方法 Take() 和 Skip() 等的分区操作可以用于分页。

Skip() 忽略根据页面大小和实际页数计算出的项数。

Take() 根据页面大小提取一定数量的项。

int pageSize = ;

int numberPages = (int)Math.Ceiling(Formula1.GetChampions().Count() /
(double)pageSize); for (int page = ; page < numberPages; page++)
{
Console.WriteLine("Page {0}", page); var racers =
(from r in Formula1.GetChampions()
orderby r.LastName, r.FirstName
select r.FirstName + " " + r.LastName).
Skip(page * pageSize).Take(pageSize); foreach (var name in racers)
{
Console.WriteLine(name);
}
Console.WriteLine();
}

对应的扩展方法 TakeWhile() 和 SkipWhile() 。

聚合操作符

聚合操作符(如 Count()、Sum()、Min()、Max()、Average() 、Aggregate() )返回一个值。

Count 返回集合项数。

var query = from r in Formula1.GetChampions()
let numberYears = r.Years.Count()
where numberYears >=
orderby numberYears descending, r.LastName
select new
{
Name = r.FirstName + " " + r.LastName,
TimesChampion = numberYears
}; foreach (var r in query)
{
Console.WriteLine("{0} {1}", r.Name, r.TimesChampion);
}

Sum 序列中的所有数字的和。

var countries = (from c in
from r in Formula1.GetChampions()
group r by r.Country into c
select new
{
Country = c.Key,
Wins = (from r1 in c
select r1.Wins).Sum()
}
orderby c.Wins descending, c.Country
select c).Take(); foreach (var country in countries)
{
Console.WriteLine("{0} {1}", country.Country, country.Wins);
}

Min 返回集合中的最小值。

Max 返回集合中的最大值。

Average 返回集合中的平均值。

Aggregate 传递一个 lambda 表达式,该表达式对所有的值进行聚合。

转换操作符

查询可以推迟到访问数据项时再执行。在迭代中使用查询时,查询会执行。而使用转换操作符会立即执行查询,把查询结果放在数组、列表或字典中。

ToList() 立即执行查询,结果放在 List<T> 类中。

List<Racer> racers =
(from r in Formula1.GetChampions() where r.Starts > orderby r.Starts descending select r).ToList(); foreach (var racer in racers)
{
Console.WriteLine("{0} {0:S}", racer);
}

也可以用 ToLookup<TKey, TElement> 类中,键可以对应多个值。

ToDictionary 支持键对应一个值。

var racers = (from r in Formula1.GetChampions()
from car in r.Cars
select new
{
Car = car,
Racer = r
}
).ToLookup(cr => cr.Car, cr => cr.Racer); if (racers.Contains("Williams"))
{
foreach (var williamsRacer in racers["Williams"])
{
Console.WriteLine(williamsRacer);
}
}

Cast 在非类型化的集合上查询

var list = new System.Collections.ArrayList(Formula1.GetChampions() as System.Collections.ICollection);

var query = from r in list.Cast<Racer>()
where r.Country == "USA"
orderby r.Wins descending
select r;
foreach (var racer in query)
{
Console.WriteLine("{0:A}", racer);
}

生成操作符

生成操作符 Range()、Empty() 和 Repear() 是返回序列的正常静态方法。

在 Linq to Objects 中,这些方法可用于 Enumerable 类。

如 需要填充一二范围的数字,此时就应使用 Range() 方法。这个方法第一个参数作为起始值,把第二个参数作为要填充的项数。

var values = Enumerable.Range(, );

foreach (var value in values)
{
Console.WriteLine(value);
}

Range() 方法不返回填充所定义值的集合,与其他方法一样,推迟查询,返回一个 RangeEnumerator。其中用 yield return 语句,来递增值。

该结果也可以与其他扩展方法一起用。

 var values = Enumerable.Range(, ).Select(n => n * );

 foreach (var value in values)
{
Console.WriteLine(value);
}

Empty() 方法返回一个不返回值的迭代器,用于需要一个集合的参数,可以给参数传递空集合。

string[] names1 = { "Hartono, Tommy" };
string[] names2 = { "Adams, Terry", "Andersen, Henriette Thaulow",
"Hedlund, Magnus", "Ito, Shu" };
string[] names3 = { "Solanki, Ajay", "Hoeing, Helge",
"Andersen, Henriette Thaulow",
"Potra, Cristina", "Iallo, Lucio" }; List<string[]> namesList =
new List<string[]> { names1, names2, names3 }; IEnumerable<string> allNames =
namesList.Aggregate(Enumerable.Empty<string>(),
(current, next) => next.Length > ? current.Union(next) : current); foreach (string name in allNames)
{
Console.WriteLine(name);
}

Repeat() 方法    返回一个迭代器,把同一个值重复特定的次数。

IEnumerable<string> strings =
Enumerable.Repeat("I like programming.", ); foreach (String str in strings)
{
Console.WriteLine(str);
}

并行Linq

System.Linq 名称空间中的包含的类 ParallelEnumerable 可以分解查询的工作, 使其分布在多个线程上。尽管 Enumerable 类给 IEnumerable<T> 接口定义了扩展方法,但 ParallelEnumerable 类的大多数扩展方法是 ParallelQuery<TSource>类的扩展。一个重要的例外是 AsParallel() 方法,扩展 IEnumerable<TSource> 接口,返回 ParallelQuery<TSource>类,所以正常的集合类可以以平行方式查询。

static IEnumerable<int> SampleData()
{
const int arraySize = ;
var r = new Random();
return Enumerable.Range(, arraySize).Select(x => r.Next()).ToList();
} var data = SampleData(); var res = (from x in data.AsParallel()
where Math.Log(x) <
select x).Average();

// 修改后的语法
var res2 = data.AsParallel().Where(x => Math.Log(x) < ).Select(x => x).Average();

与Linq查询一样,编译器会修改语法,调用AsParallel()、Where()、Select()、Average()。 Asparallel() 方法调用用 ParallelEnumerable 类定义,扩展 IEnumberable<T>接口,所以可以对简单的数组调用它。 AsParallel() 方法返回 ParallelQuery<TSource>。因为返回的类型,所以编译器选择的Where()方法是ParallelEnumerable.Where(),而不是 Enumerable.Where()。 其他的 Select 和 Average 也是来自 ParallelEnumerable 类。与 Enumerable 类相反,对于 ParllelEnumerable类,查询是分区的,以便多个线程可以同时处理该查询。集合可以分为多个部分,其中每个部分由不同的线程处理,以筛选其余项。完成分区的工作后,就需要合并,获得所有部分的总和。

运行时,可以打开任务管理器,就可以发现所有的CPU都处于忙碌的状态。

分区器

AsParallel()方法不仅扩展了 IEnumerable<T> 接口,还扩展了 Partitioner 类。通过它,可以影响创建的分区。

手动创建一个分区器

var result = (from x in Partitioner.Create(data).AsParallel() where Math.Log(x) <  select x).Average();

也可以调用WithExecutionMode() 和 WithDegreeOfParallelism() 方法,影响并行机制。对于 WithExecutionMode() 方法传递 ParallelExecutionMode的一个Default值或者 ForceParallelism值。默认情况下,并行Linq避免使用系统开销很高的并行机制。对于WithDegreeOfParallelism()方法,可以传递一个整数值,制定并行运行的最大任务数。

取消

.NET 提供一个标准方法,来取消长时间运行的任务,也适用于并行Linq。

要取消长时间运行的查询可以给查询添加WithCancellation() 方法,并传递一个 CancellactionToken令牌作为参数。CancelllationToken令牌从CancellactionTokenSource类中创建。该查询在单独的线程中运行,在该线程中,捕获一个OperationCanceledException类型的异常。如果取消了查询就出发这个异常。在主线程中,调用CancellationTokenSource类的Cancel()方法可以取消任务。

 var data = SampleData();
CancellationTokenSource cts = new CancellationTokenSource(); Task.Factory.StartNew(() =>
{
try
{
var res = (from x in data.AsParallel().WithCancellation(cts.Token)
where Math.Log(x) <
select x).Average();
Console.WriteLine("query finished, sum:{0}",res);
}
catch (OperationCanceledException ex)
{
Console.WriteLine("canceled!");
Console.WriteLine(ex.Message);
}
}); string input = Console.ReadLine();
if (input.ToLower().Equals("y"))
{
cts.Cancel();
Console.WriteLine("canceled 2!");
}

表达式树

扩展方法需要将一个委托类型作为参数,这就可以将 lambda 表达式赋予参数。 lambda 表达式赋予 Expression<T>类型的参数。C#编译器根据类型给 lambda表达式定义不同的行为。如果类型是 Express<T>,编译器就从 lambda 表达式中创建一个表达式树,并存储在程序集中。这样,就可以在运行期间分析表达式树,并进行优化,以便于查询数据源。

http://www.cnblogs.com/mcgrady/archive/2014/05/17/3732694.html#_label5

private static void DisplayTree(int indent, string message, Expression expression)
{
string output = String.Format("{0} {1} ! NodeType: {2}; Expr: {3} ",
"".PadLeft(indent, '>'), message, expression.NodeType, expression); indent++;
switch (expression.NodeType)
{
case ExpressionType.Lambda:
Console.WriteLine(output);
LambdaExpression lambdaExpr = (LambdaExpression)expression;
foreach (var parameter in lambdaExpr.Parameters)
{
DisplayTree(indent, "Parameter", parameter);
}
DisplayTree(indent, "Body", lambdaExpr.Body);
break;
case ExpressionType.Constant:
ConstantExpression constExpr = (ConstantExpression)expression;
Console.WriteLine("{0} Const Value: {1}", output, constExpr.Value);
break;
case ExpressionType.Parameter:
ParameterExpression paramExpr = (ParameterExpression)expression;
Console.WriteLine("{0} Param Type: {1}", output, paramExpr.Type.Name);
break;
case ExpressionType.Equal:
case ExpressionType.AndAlso:
case ExpressionType.GreaterThan:
BinaryExpression binExpr = (BinaryExpression)expression;
if (binExpr.Method != null)
{
Console.WriteLine("{0} Method: {1}", output, binExpr.Method.Name);
}
else
{
Console.WriteLine(output);
}
DisplayTree(indent, "Left", binExpr.Left);
DisplayTree(indent, "Right", binExpr.Right);
break;
case ExpressionType.MemberAccess:
MemberExpression memberExpr = (MemberExpression)expression;
Console.WriteLine("{0} Member Name: {1}, Type: {2}", output,
memberExpr.Member.Name, memberExpr.Type.Name);
DisplayTree(indent, "Member Expr", memberExpr.Expression);
break;
default:
Console.WriteLine();
Console.WriteLine("{0} {1}", expression.NodeType, expression.Type.Name);
break;
}
} static void Main()
{
Expression<Func<Racer, bool>> expression = r => r.Country == "Brazil" && r.Wins > ;
DisplayTree(, "Lambda", expression);
}

LINQ提供程序

LINQ提供程序为特定的数据源实现了标准的查询操作符。LINQ提供程序也许会实现比LINQ定义的更多扩展方法,但至少要实现标准操作符。LINQ to XML 如 Extensions 类定义 Elements()、Descendants() 和 Ancestors() 。

LINQ提供程序的实现方案是根据名称空间和第一个参数的类型来选择的。如 LINQ to Objects 定义 Where() 方法的参数 和 在 LINQ to Entities 中定义的 Where() 的方法参数不同。

重要的总结

C# LINQ(10)的更多相关文章

  1. 那天有个小孩跟我说LINQ(五)转载

    2  LINQ TO SQL(代码下载)      我们以一个简单的销售的业务数据库为例子         表结构很简单:Users(购买者(用户)表),Products(产品信息表),Sales(销 ...

  2. Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录

    1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...

  3. Linq(一)

    概述 LINQ是.NET框架的扩展,它允许我们以使用SQL查询数据库的方式来查询数据集合. 使用LINQ,你可以从数据库.程序对象集合以及XML文档中查询数据. 需要注意的是,对于比较简单的功能,与其 ...

  4. 2016windows(10) wamp 最简单30分钟thrift入门使用讲解,实现php作为服务器和客户端的hello world

    2016最简单windows(10) wamp 30分钟thrift入门使用讲解,实现php作为服务器和客户端的hello world thrift是什么 最简单解释 thrift是用来帮助各个编程语 ...

  5. Neutron 理解(10):虚拟专用网(VPN)虚拟化 [How Neutron implements VPN Virtualization]

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  6. 基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

    数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章<Winform开发框架之通用数据导入导出操作>介绍了在Winform ...

  7. Python的平凡之路(10)

    异步IO 数据库 队列 缓存 1.Gevent协程 定义:用户态的轻量级线程.协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下 ...

  8. varchar(10)与nvarchar(10)有什么区别

    前者是非unicode型,存储字符按1个算(内部空间存储占1字节),存储汉字的话按2个算, 就是可以存10个字符或者5个汉字 后者是unicode型,存储什么都是按1个算(内部空间存储占2字节), 就 ...

  9. Spring入门(10)-Spring JDBC

    Spring入门(10)-Spring JDBC 0. 目录 JdbcTemplate介绍 JdbcTemplate常见方法 代码示例 参考资料 1. JdbcTemplate介绍 JdbcTempl ...

随机推荐

  1. vimium快捷键修改

    vimium是一款很好用的浏览器插件,可以用键盘来进行一些操作. 需要在浏览器的扩展程序商店里下载相应的插件,然后可以右键点击插件打开选项进行个性化的配置. map+字母+功能描述 功能描述从opti ...

  2. 记录一次 hadoop yarn resourceManager无故切换的故障

    某日 收到告警 线上集群rm切换 观察resourcemanager 日志报错如下 这行不明显 再看看其他日志报错 在 app attempt_removed 时候发生了空指针错误 break; ca ...

  3. Thinkphp5+Layui上传图片

    ThinkPHP是一个免费开源的,快速.简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的.ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能 ...

  4. PHP的四种运行方式

    一丶cgi协议模式 cgi模式通用网关接口(Common Gateway Interface),它允许web服务器通过特定的协议与应用程序通信,调用原理大概为:用户请求->Web服务器接收请求- ...

  5. 通过ImageReader进行图像裁剪时出现NoSuchElementException异常

    首先放上最初的Image工具类 package util; import java.awt.Rectangle; import java.awt.image.BufferedImage; import ...

  6. windows系统 MySQL8.0.12详细安装步骤及基本使用教程

    转载  https://blog.csdn.net/xiezhiming1234/article/details/82860339

  7. codeforce B. Petya and Exam

    wa一万次难受. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm& ...

  8. Win10怎么添加开机启动项?Win10添加开机自动运行软件三种方法

    Win10管理开机启动项的方法相信大家已经非常熟悉,msconfig命令各系统都通用,那么很多用户发觉Win10和Win7 XP等系统不同,没有启动文件夹,那么我们怎么添加开机启动项呢?如晨软件或程序 ...

  9. C#学习基础资料记录---字典(Dictionary),时间表示方法(DateTime.Now),文件操作

    1.字典 https://www.cnblogs.com/gengaixue/p/4002244.html 2.时间的表示方法 DateTime.Now的多种用法 https://www.cnblog ...

  10. HTML练习二--动态加载轮播图片

    接上一篇https://www.cnblogs.com/shuaimeng/p/11106655.html demo下载: https://pan.baidu.com/s/1dhvzHwTHKiguy ...