class RangeProjection
{
static void Main()//用Select方法和匿名类型进行投影
{
var collection = Enumerable.Range(0, 10)
.Where(x => x % 2 != 0)
//Where里面创建变量x 1 2 3 4 5 6 7 8 9
//执行 new { Original = x, SquareRoot = Math.Sqrt(x) }
.Reverse()
//我们得到了0-9的奇数(逆序),让我们创建一个类型来封装数字的平方根以及原始数字
.Select(x => new { Original = x, SquareRoot = Math.Sqrt(x) });
//x = 9 7 5
//collection为 Enumerable.WhereSelectEnumerableIterator<int,<>f__AnonymousType2<int,double>>
foreach (var element in collection)
//先collection 后 in where被调用, 后 var element
//var element被多次赋值 为 Original = 9, SquareRoot = 3.0
//Original = 7, SquareRoot = 2.6457513110645907
//Original = 5, SquareRoot = 2.23606797749979
//Original = 3, SquareRoot = 1.7320508075688772
//Original = 1, SquareRoot = 1.0
//in估计是
//in 不再调用where 调用select
{
Console.WriteLine("sqrt({0})={1}",
element.Original,
element.SquareRoot);
}
}
}
Enumerable中最重要的投影方法就是Select,操纵一个IEnumerable<TSource>,
把它投影成一个IEnumerable<TResult>。具体的投影是通过一个
Func<TSource,TResult>来完成的,它代表要在每个元素上执行的转换,
采用的是委托的形式。Select和List<T>中的ConvertAll方法很像,但它能
操纵任意可枚举的集合。 它利用了"延迟执行"技术,只有在每个元素被请求的时候
才真正执行投影。
匿名类型和Lambda表达式以及LINQ表达式一起使用是最有用的。
这一次的Collection的类型不是IEnumerable<int>,
而是IEnumerable<Something>,其中Something是由编译器创建的匿名类型。
我们不能显式地指定集合变量的类型,除非指定成非泛型的IEnumerable类型
或object。正是因为使用了隐式类型(var),所以我们才能在输出结果时使用Original
和SquareRoot属性。
Select方法不一定非得使用一个匿名类型--我们可以只选择数字的平方根,而
丢弃原始值。这时的结果为IEnumerable<double>类型。除此之外,还可以
手动写一个类型来封装整数及其平方根--只是在当前这种情况下,使用匿名类型
是最容易的罢了。
输出
sqrt(9)=3
sqrt(7)=2.64575131106459
sqrt(5)=2.23606797749979
sqrt(3)=1.73205080756888
sqrt(1)=1