C# LINQ(10)
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)的更多相关文章
- 那天有个小孩跟我说LINQ(五)转载
2 LINQ TO SQL(代码下载) 我们以一个简单的销售的业务数据库为例子 表结构很简单:Users(购买者(用户)表),Products(产品信息表),Sales(销 ...
- Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录
1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...
- Linq(一)
概述 LINQ是.NET框架的扩展,它允许我们以使用SQL查询数据库的方式来查询数据集合. 使用LINQ,你可以从数据库.程序对象集合以及XML文档中查询数据. 需要注意的是,对于比较简单的功能,与其 ...
- 2016windows(10) wamp 最简单30分钟thrift入门使用讲解,实现php作为服务器和客户端的hello world
2016最简单windows(10) wamp 30分钟thrift入门使用讲解,实现php作为服务器和客户端的hello world thrift是什么 最简单解释 thrift是用来帮助各个编程语 ...
- Neutron 理解(10):虚拟专用网(VPN)虚拟化 [How Neutron implements VPN Virtualization]
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- 基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章<Winform开发框架之通用数据导入导出操作>介绍了在Winform ...
- Python的平凡之路(10)
异步IO 数据库 队列 缓存 1.Gevent协程 定义:用户态的轻量级线程.协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下 ...
- varchar(10)与nvarchar(10)有什么区别
前者是非unicode型,存储字符按1个算(内部空间存储占1字节),存储汉字的话按2个算, 就是可以存10个字符或者5个汉字 后者是unicode型,存储什么都是按1个算(内部空间存储占2字节), 就 ...
- Spring入门(10)-Spring JDBC
Spring入门(10)-Spring JDBC 0. 目录 JdbcTemplate介绍 JdbcTemplate常见方法 代码示例 参考资料 1. JdbcTemplate介绍 JdbcTempl ...
随机推荐
- vimium快捷键修改
vimium是一款很好用的浏览器插件,可以用键盘来进行一些操作. 需要在浏览器的扩展程序商店里下载相应的插件,然后可以右键点击插件打开选项进行个性化的配置. map+字母+功能描述 功能描述从opti ...
- 记录一次 hadoop yarn resourceManager无故切换的故障
某日 收到告警 线上集群rm切换 观察resourcemanager 日志报错如下 这行不明显 再看看其他日志报错 在 app attempt_removed 时候发生了空指针错误 break; ca ...
- Thinkphp5+Layui上传图片
ThinkPHP是一个免费开源的,快速.简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的.ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能 ...
- PHP的四种运行方式
一丶cgi协议模式 cgi模式通用网关接口(Common Gateway Interface),它允许web服务器通过特定的协议与应用程序通信,调用原理大概为:用户请求->Web服务器接收请求- ...
- 通过ImageReader进行图像裁剪时出现NoSuchElementException异常
首先放上最初的Image工具类 package util; import java.awt.Rectangle; import java.awt.image.BufferedImage; import ...
- windows系统 MySQL8.0.12详细安装步骤及基本使用教程
转载 https://blog.csdn.net/xiezhiming1234/article/details/82860339
- codeforce B. Petya and Exam
wa一万次难受. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm& ...
- Win10怎么添加开机启动项?Win10添加开机自动运行软件三种方法
Win10管理开机启动项的方法相信大家已经非常熟悉,msconfig命令各系统都通用,那么很多用户发觉Win10和Win7 XP等系统不同,没有启动文件夹,那么我们怎么添加开机启动项呢?如晨软件或程序 ...
- C#学习基础资料记录---字典(Dictionary),时间表示方法(DateTime.Now),文件操作
1.字典 https://www.cnblogs.com/gengaixue/p/4002244.html 2.时间的表示方法 DateTime.Now的多种用法 https://www.cnblog ...
- HTML练习二--动态加载轮播图片
接上一篇https://www.cnblogs.com/shuaimeng/p/11106655.html demo下载: https://pan.baidu.com/s/1dhvzHwTHKiguy ...