回顾:
前面我们说过LINQ查询表达式只能操作实现了IEnumerable<T>接口的对象。
再来看前面几个例子,我们通过数组来使用了LINQ查询表达式,那是否Array实现了IEnumerable<T>接口了?
可以看到正式的Array定义如下:
//Array类型看上去并没有实现查询表达式所需要的接口
public abstract class Array:ICloneable,IList,ICollection,IEnumerable
{....}
然而你通过数组的实例来点 可以点出很多原本在Array里并没有提供的方法。
想想你可能马上就想到了扩展方法,对,是其他类型在幕后对Array类型做了扩展,所以我们才可以得到那些功能.
目标:
1.Linq查询表达式内部实现机制
2.Linq查询运算符的演变过程
一、LINQ查询表达式内部实现机制:
LINQ可以操作数组类型,也可以操作System.Collections.Generic命名空间的成员类型如:List<T>
使用LINQ查询非泛型的集合
System.Enumerable类型提供很多对IEnumerable接口的扩展方法
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace ConsoleApplication4
{
class Test1
{
static void Main()
{
ArrayList list = new ArrayList();
list.Add("Asp.net");
list.Add(111);
list.Add("Ajax");
//通过扩展方法OfType<T>把ArrayList转换成了一个兼容于IEnumber<T>的类型
IEnumerable<string> myList=list.OfType<string>();
var item = from g in myList
where g.Length > 5
orderby g
select g;
Array.ForEach<string>(item.ToArray<string>(), s => { Console.WriteLine(s); });
}
}
}
//注意非泛型类型可以包含任何类型的项,以ArrayList为例,它接受的是Object类型的项
//使用OfType<T>可以过滤出类型不满足T的类型的项
正式的System.Linq.Enumerable的定义如下:
Code Enumerable的定义
namespace System.Linq
{
//这个类型扩展了很多早先2.0里类型没有的方法 这些都是底层的实现
public static class Enumerable
{
//扩展了IEnumerable接口,相当于在IEnumerable接口里添加了一个OfType<Tresult>的泛型方法
public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return OfTypeIterator<TResult>(source);
}
//扩展了IEnumerable<T>接口 其接受一个参数并返回一个bool类型的委托
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
return WhereIterator<TSource>(source, predicate);
}
}
}
二、Linq查询运算符的演变过程
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
/**//***********************************************************************************************************
Func<TResult>委托 封装一个不具有参数但却返回 TResult 参数指定的类型值的方法。
Func<T,TResult>委托 封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。
Func<T,T,TResult>委托 封装一个具有二个参数并返回 TResult 参数指定的类型值的方法。
Func<T,T,T,TResult>委托 封装一个具有三个参数并返回 TResult 参数指定的类型值的方法。
Func<T,T,T,T,TResult>委托 封装一个具有四个参数并返回 TResult 参数指定的类型值的方法。
LINQ查询运算符的演变过程
************************************************************************************************************/
class TestApp
{
static void Main()
{
var s = new[] { "Hello Word!", "Study Hard", "Asp.net 3.0", ".NET FrameWork3.5" };//集合初始化器构建一个隐式数组
Console.WriteLine("第一种方式:");
//使用System.Enumerable类型里的扩展方法和原始代理建立查询表达式
Func<string, bool> filter = new Func<string, bool>(Fileter);
Func<string, string> itemToProcess = new Func<string, string>(ProcessItem);
var list1 = s.Where(filter).OrderBy(itemToProcess).Select(itemToProcess);//实例调用扩展方法
Array.ForEach<string>(list1.ToArray<string>(), g => { Console.WriteLine(g); });
Console.WriteLine("第二种方式:");
//使用System.Enumerable类型里的扩展方法和匿名方法来建立查询表达式
Func<string, bool> searchFilter = delegate(string g)
{
return g.Length > 15;
};
Func<string, string> item = delegate(string g)
{
return g;
};
var list2 = Enumerable.Where(s, searchFilter).OrderBy(item).Select(item);//静态调用扩展方法
Array.ForEach<string>(list2.ToArray<string>(), g => { Console.WriteLine(g); });
//使用lambda表达式来建立查询表达式
Console.WriteLine("第三种方式:");
var list3 = s.Where(g => g.Length > 15).OrderBy(g => g).Select(g => g);//通过Lambda表达式建立查询表达式 把匿名方法都代替成Lambda表达式
Array.ForEach<string>(list3.ToArray<string>(), g => { Console.WriteLine(g); });
Console.WriteLine("第四种方式:");
var list4 = from g in s where g.Length > 15 orderby g select g; //哇!LINQ查询表达式就1行代码就完成了上面所做的工作
Array.ForEach<string>(list4.ToArray<string>(), g => { Console.WriteLine(g); });
//其实新的语法就是简化了调用Enumerable类型定义的扩展方法的简化符号
}
static bool Fileter(string s) { return s.Length > 15; }
static string ProcessItem(string s) { return s; }
}
}
总结:
查询表达式是用各种查询运算符建立的
查询运算符只是调用了由System.linq命名空间下的Enumerable定义的扩展方法的简化符号
Enumerable的许多方法都要求代理(特别是Func<>)作为参数
在C#3.0 任何要求代理参数的方法都可以传入一个Lambda表达式
Lambda是伪造的匿名方法
匿名方法是对指派一个原始代理然后手工建立一个代理目标方法的简化符号.
|