网站手机端怎么做,学习网,简单的网站源码,网店代运营费用多少钱前言 上一篇《从LINQ开始之LINQ to Objects#xff08;上#xff09;》主要介绍了LINQ的体系结构、基本语法以及LINQ to Objects中标准查询操作符的使用方法。
本篇则主要讨论LINQ to Objects中的扩展方法以及延迟加载等方面的内容。 扩展方法 1.扩展方法简介 扩展方法能够向…前言 上一篇《从LINQ开始之LINQ to Objects上》主要介绍了LINQ的体系结构、基本语法以及LINQ to Objects中标准查询操作符的使用方法。
本篇则主要讨论LINQ to Objects中的扩展方法以及延迟加载等方面的内容。 扩展方法 1.扩展方法简介 扩展方法能够向现有类型“添加”方法而无需创建新的派生类型、重新编译或其他方式修改原始类型。扩展方法是静态方法它是类的一部分但实际没有放在类的源代码当中。
下面我们来看一个简单示例为上一篇中定义的Employee类添加扩展方法GetSeniority获取员工在本公司的工龄
public static class EmployeeExtension{ /// summary/// 计算员工在本公司的工龄/// /summary/// param nameemployee/param/// returns/returnspublic static long GetSeniority(this Employee employee) {TimeSpan ts DateTime.Now - employee.EntryDate; return (long)ts.TotalDays / 365;}
}
接下来遍历employees列表输出所有员工的姓名及工龄 //获取所有员工的姓名及在本公司的工龄foreach (var employee in employees){Console.WriteLine(EmployeeName: employee.EmployeeName Seniority: employee.GetSeniority());} //******************************Output*******************************//EmployeeName: Mike Seniority: 1//EmployeeName: Jack Seniority: 10//EmployeeName: Adolph Seniority: 0//EmployeeName: Antony Seniority: 6//EmployeeName: Asa Seniority: 2//EmployeeName: Bernie Seniority: 9//EmployeeName: Carl Seniority: 2//EmployeeName: Duncan Seniority: 7//EmployeeName: Aimee Seniority: 0//EmployeeName: Cassie Seniority: 3//*******************************************************************
由示例可以看出
1扩展方法中可以访问被扩展类型的所有公有方法和属性。
2第一个参数是要扩展的类型以this关键字开头。
3即使扩展方法是静态的也要使用标准的实例方法语法进行调用。
下面的示例演示了如果扩展方法与类中的某个方法具有相同的签名则扩展方法不会被调用。在Employee类中定义方法SayHello public void SayHello() {Console.WriteLine(Hello , Im EmployeeName);}
在EmployeeExtension类中为Employee类定义扩展方法SayHello public static void SayHello(this Employee employee) {Console.WriteLine(Hello , Im employee.EmployeeName ,this is Extension Method);}
此时新入职了一位同事Dave调用SayHello方法向大家问好 Employee dave new Employee(011, Dave, 30, new DateTime(2017, 5, 25), Sex.Male, Department.PD, 200000, new string[] { climbing });dave.SayHello(); //******************************Output*******************************//Hello , Im Dave//*******************************************************************
注意此时调用的是Employee类下面的SayHello方法。
2.使用扩展方法来扩展接口 把方法扩展到某个接口中实现该接口的多个类就可以使用相同的实现代码。
以下示例介绍了扩展方法扩展接口的使用场景首先定义了一个接口IHobby接口中包含Play方法
public interface IHobby{ void Play();
}
分别创建类Reading、Swimming、Shopping实现IHobby接口
public class Reading : IHobby{ public void Play() {Console.WriteLine(Im Reading.);}
}public class Swimming : IHobby{ public void Play() {Console.WriteLine(Im Swimming.);}
}public class Shopping : IHobby{ public void Play() {Console.WriteLine(Im Shopping.);}
}
此时我们需要在实现IHobby接口的类增加一个的方法ShareFeelings输出Im happpy.当然可以在接口上新增一个方法然后将实现该接口的类逐个添加ShareFeelings方法假如实现该接口的类很多使用扩展方法就可以大大的减少代码的修改量测试起来也非常简单。 public static void ShareFeelings(this IHobby hobby) {Console.WriteLine(Im happy.);}
使用接口变量来调用扩展方法 IHobby hobby new Reading();hobby.ShareFeelings(); //******************************Output*******************************//Im happy.//*******************************************************************
3.LINQ中的扩展方法 LINQ为IEnumerableT接口提供给了各种扩展方法以便用户在实现了该接口的任意集合上使用LINQ查询。本节主要研究LINQ中Where扩展方法的实现这个扩展方法位于System.Linq命名空间下的Enumerable类中。
public static IEnumerableTSource WhereTSource(this IEnumerableTSource source, FuncTSource, bool predicate) { if (source null) throw Error.ArgumentNull(source); if (predicate null) throw Error.ArgumentNull(predicate); if (source is IteratorTSource) return ((IteratorTSource)source).Where(predicate); if (source is TSource[]) return new WhereArrayIteratorTSource((TSource[])source, predicate); if (source is ListTSource) return new WhereListIteratorTSource((ListTSource)source, predicate); return new WhereEnumerableIteratorTSource(source, predicate);}
由上述代码可以看出Where方法是对IEnumberable接口的扩展需要传入一个委托参数predicate该委托要求返回布尔类型。假设我们对ListT类型的对象调用Where方法则返回一个WhereListIteratorTSource对象。WhereListIteratorTSource类派生自IteratorTSource类,下面是IteratorTSource类的源码这里我们只需要注意GetEnumerator方法该方法对于同一个线程返回同一个迭代器不同线程则克隆一个并将state属性设置为1。 abstract class IteratorTSource : IEnumerableTSource, IEnumeratorTSource{ int threadId;internal int state;internal TSource current; public Iterator() {threadId Thread.CurrentThread.ManagedThreadId;} public TSource Current {get { return current; }} public abstract IteratorTSource Clone(); public virtual void Dispose() {current default(TSource);state -1;} public IEnumeratorTSource GetEnumerator() { if (threadId Thread.CurrentThread.ManagedThreadId state 0) {state 1; return this;}IteratorTSource duplicate Clone();duplicate.state 1; return duplicate;} public abstract bool MoveNext(); public abstract IEnumerableTResult SelectTResult(FuncTSource, TResult selector); public abstract IEnumerableTSource Where(FuncTSource, bool predicate);object IEnumerator.Current {get { return Current; }}IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator();} void IEnumerator.Reset() { throw new NotImplementedException();}}
此时再回到WhereListIteratorTSource类该类重写了MoveNext方法。首先调用GetEnumerator方法获得一个枚举器在While循环中只要MoveNext方法返回true就用Current属性获得集合当前的元素并使用委托predicate引用的方法处理该元素返回剩余元素中满足条件的第一个元素。当遍历结束调用Dispose方法释放非托管资源并将state属性设置为-1。 class WhereListIteratorTSource : IteratorTSource{ListTSource source;FuncTSource, bool predicate;ListTSource.Enumerator enumerator; public WhereListIterator(ListTSource source, FuncTSource, bool predicate) { this.source source; this.predicate predicate;} public override IteratorTSource Clone() { return new WhereListIteratorTSource(source, predicate);} public override bool MoveNext() { switch (state) { case 1:enumerator source.GetEnumerator();state 2; goto case 2; case 2: while (enumerator.MoveNext()) {TSource item enumerator.Cur rent; if (predicate(item)) {current item; return true;}}Dispose(); break;} return false;} public override IEnumerableTResult SelectTResult(FuncTSource, TResult selector) { return new WhereSelectListIteratorTSource, TResult(source, predicate, selector);} public override IEnumerableTSource Where(FuncTSource, bool predicate) { return new WhereListIteratorTSource(source, CombinePredicates(this.predicate, predicate));}}
源码传送门http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,dc4c4c53ff606bc0 延迟加载 1.延迟执行 在运行期间定义查询表达式时查询不会运行只有在迭代时才进行计算。
下面的示例定义了一个LINQ查询从集合中找出姓名以A开头的所有员工因为迭代在查询定义时不会进行而是在执行每个foreach语句时进行。 var nameStartWithA from e in employees where e.EmployeeName.StartsWith(A) select e;Console.WriteLine(First iteration : ); foreach (var item in nameStartWithA){Console.WriteLine(item.EmployeeName);}Console.WriteLine();employees.Add(new Employee(011, Lily, 25, new DateTime(2017, 5, 29), Sex.Female, Department.HR, 100000, new string[] { shopping }));employees.Add(new Employee(012, Leo, 28, new DateTime(2017, 5, 29), Sex.Male, Department.IT, 200000, new string[] { reading }));employees.Add(new Employee(013, Amelia, 29, new DateTime(2017, 5, 29), Sex.Female, Department.PD, 200000, new string[] { reading, run }));employees.Add(new Employee(014, Ava, 32, new DateTime(2017, 5, 29), Sex.Female, Department.PD, 400000, new string[] { swimming }));Console.WriteLine(Second iteration : ); foreach (var item in nameStartWithA){Console.WriteLine(item.EmployeeName);} //******************************Output*******************************//First iteration ://Adolph//Antony//Asa//Aimee//Second iteration ://Adolph//Antony//Asa//Aimee//Amelia//Ava//*******************************************************************
补充延迟加载的工作原理可从上一章节中对源码的分析得出。
2.立即执行 查询在定义表达式时立即执行而不是在迭代中进行。通过调用ToArray()、ToList()等扩展方法可以实现此项操作。
下面我们修改上一节中的示例来说明 var nameStartWithA (from e in employees where e.EmployeeName.StartsWith(A) select e).ToList();Console.WriteLine(First iteration : ); foreach (var item in nameStartWithA){Console.WriteLine(item.EmployeeName);}Console.WriteLine();employees.Add(new Employee(011, Lily, 25, new DateTime(2017, 5, 29), Sex.Female, Department.HR, 100000, new string[] { shopping }));employees.Add(new Employee(012, Leo, 28, new DateTime(2017, 5, 29), Sex.Male, Department.IT, 200000, new string[] { reading }));employees.Add(new Employee(013, Amelia, 29, new DateTime(2017, 5, 29), Sex.Female, Department.PD, 200000, new string[] { reading, run }));employees.Add(new Employee(014, Ava, 32, new DateTime(2017, 5, 29), Sex.Female, Department.PD, 400000, new string[] { swimming }));Console.WriteLine(Second iteration : ); foreach (var item in nameStartWithA){Console.WriteLine(item.EmployeeName);} //******************************Output*******************************//First iteration ://Adolph//Antony//Asa//Aimee//Second iteration ://Adolph//Antony//Asa//Aimee//*******************************************************************
从输出结果中可以看出两次迭代输出的结果相同但是集合中值改变了。
示例代码下载https://github.com/Answer-Geng/LINQ
原文地址http://www.cnblogs.com/Answer-Geng/p/6905630.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注