西安网站开发工资,网页转app工具,给前端做网站的图片叫什么,网站开发中涉及的侵权行为文章目录 第三章 C#3#xff1a;LINQ及相关特性3.1 自动实现属性#xff08;*#xff09;3.2 隐式类型 var#xff08;*#xff09;3.3 对象和集合初始化3.3.1 对象初始化器3.3.2 集合初始化器 3.4 匿名类型3.4.1 基本语法和行为3.4.2 编译器生成类型3.4.3 匿名类型的局限… 文章目录 第三章 C#3LINQ及相关特性3.1 自动实现属性*3.2 隐式类型 var*3.3 对象和集合初始化3.3.1 对象初始化器3.3.2 集合初始化器 3.4 匿名类型3.4.1 基本语法和行为3.4.2 编译器生成类型3.4.3 匿名类型的局限性 3.5 lambda 表达式3.5.1 捕获变量3.5.2 表达式树 3.6 扩展方法3.6.1 声明扩展方法3.6.2 调用扩展方法3.6.3 扩展方法的链式调用 3.7 查询表达式3.7.1 从 C# 到 C# 的查询表达式转换3.7.2 范围变量和隐形标识符3.7.3 选择使用哪种 LINQ 语法 3.8 终极形态LINQ 第三章 C#3LINQ及相关特性
3.1 自动实现属性*
3.2 隐式类型 var*
3.3 对象和集合初始化
3.3.1 对象初始化器 对象初始化器的作用只是表达应该如何初始化每个属性。
注意只有在使用对象初始化器或者集合初始化器时构造器的参数列表才再以省略。
如果初始化值“” 右边的内容是一个普通的表达式那么会先计算该表达式的值然后将结果传给属性对应的 set 访问器。如果初始化值是另一个对象初始化器则不会调用 set 访问器而会调用 get 访问器然后将嵌套对象初始化器得到的结果应用于由 get 访问器返回的属性。 上述代码等同于以下代码 3.3.2 集合初始化器
集合初始化器多用于创建新集合。下面这行代码创建了一个字符串集合并为其添加初始值 编译器会将以上代码转换成一个构造器调用其后紧跟一系列 Add 方法的调用 对于 DictionaryTKey, TValue添加元素的方法是 Add (key, value) 编译器把每个元素初始化器都看作一个 Add 调用。如果元素初始化器没有大括号则将其作为单个参数传递给 Add 方法。上述字典的例子等同于如下代码 只有实现了 IEnumerable 接口的类型才能够使用集合初始化器。
3.4 匿名类型
3.4.1 基本语法和行为
使用匿名类型可以更精练地表达“一次性”的类型需求同时还不失静态类型的优势 匿名类型的语法类似于对象初始化器但无须指定类型名称只需要 new 关键字、左大括号、属性以及右大括号。这一形式称为匿名对象创建表达式。 声明 player 变量使用了 var 关键字因为所创建的类型是匿名类型所以只能用 var 来声明也可以使用 object 来声明不过意义不大。 以上代码依然属于静态类型的范畴。Visual Studio 会为 player 变量自动设置 Name 和 Score 属性。如果要访问一个不存在的属性比如 player.Points则编译器会报错。 属性的类型是根据赋值的类型进行推断的player.Name 是 string 类型player. Score 是 int 类型。
投射初始化器
可以从其他对象复制属性或字段到新对象中并且二者的属性或字段名称相同。 上述例子中除了 CustomerName其他属性都使用了投射初始化器。以上代码的运行结果和下面这种显式写出每个属性名称得到的结果是相同的 如果目标属性或字段的名称与源名称一致那么可以交由编译器来推断名称如以下代码 可以直接简化为 说明 尽管以上两种形式的代码结果相同但不是所有行为都相同。 例如在项目中将 Address 属性重命名为 CustomerAddress若使用投射初始化器那么 flattenedItem.Address 也将变为 flattenedItem.CustomerAddress。 3.4.2 编译器生成类型
虽然源码中没有出现匿名类型的名称但编译器需要为它生成一个类型。
它在执行期没有任何特殊之处对于执行期来说也只是一个普通的类型而已。该类型的名称不是一个有效的 C# 名称。
关于该类型还有几个比较有意思的特征其中一些得到了语言规范层面的保证
它是一个类保证。其基类是 object 保证。该类是密封的不保证虽然非密封的类并没有什么优势。属性是只读的保证。构造器的参数名称与属性名称保持一致不保证有时对于反射有用。对于程序集是 internal 的不保证在处理动态类型时会比较棘手。该类会覆盖 GetHashCode() 和Equals() 方法两个匿名类型只有在所有属性都等价的情况下才等价可以正常处理 null 值。只保证会覆盖这两个方法但不保证散列值的计算方式。覆盖并完善 ToString() 方法用于呈现各属性名称及其对应值。这一点不保证但对于问题诊断来说作用重大。该类型为泛型类其类型形参会应用于每一个属性。具有相同属性名称但属性类型不同的匿名类型会使用相同的泛型类型但拥有不同的类型实参。这一点不保证不同编译器的实现方式不同。如果两个匿名对象创建表达式使用相同的属性名称具有相同的属性类型以及属性顺序 并且在同一个程序集中那么这两个对象的类型相同。
可以利用第 10 点使用匿名类型来创建隐式类型数组 3.4.3 匿名类型的局限性
难以应用于方法签名中。即 难以在多处使用同一个匿名类型。匿名类型不提供任何数据封装。即匿名类型中不能有校验也不能添加任何行为。
3.5 lambda 表达式
3.5.1 捕获变量
给出如下设计好的代码示例 instanceField 是 CapturedVariablesDemo 类的一个实例字段被 lambda 表达式所捕获。methodParameter 是 CreateAction 方法的一个参数被 lambda 表达式所捕获。methodLocal 是 CreateAction 方法中的一个局部变量被 lambda 表达式所捕获。uncaptured 是 CreateAction 方法中的一个局部变量因为没有被 lambda 表达式使用所以不属于捕获变量。lambdaParameter 是 lambda 表达式自己的参数不属于捕获变量。lambdaLocal 是 lambda 表达式内部的局部变量不属于捕获变量。
通过生成类来实现捕获变量
没有捕获任何变量编译器会创建一个静态方法不需要额外的上下文。仅捕获了实例字段编译器会创建一个实例方法。实例字段的捕获数目没有影响只需要一个 this 便都可以访问。捕获了局部变量或者参数编译器会创建一个私有的嵌套类用于保存上下文信息在该类中创建一个实例方法用于容纳原 lambda 表达式内容并使用嵌套类来访问捕获变量。
应用上述规则编译器转义后的代码如下 说明 具体实现细节因编译器而异。例如对于没有捕获变量的 lambda 表达式编译器可能会创建一个包含一个实例方法的嵌套类而不是创建一个静态方法。委托的执行效率会因创建方式的不同而略有差异。这里只描述编译器为访问捕获变量所做的那些必要、基本的工作 其复杂度可能根据实际需要而增加。 局部变量的多次实例化
简单起见下列代码不捕获参数和实例字段只捕获一个局部变量 在这段代码中每次声明 text 时该变量就完成一次实例化因此每个 lambda 表达式捕获的都是不同的变量实例于是 5 个完全独立的 text 变量被分别捕获。虽然这段代码中变量初始化后没有任何修改操作 但编译器的做法是每次初始化都创建一个不同的生成类型实例。编译器转义后的代码如下 多个作用域下的变量捕获
循环的每次迭代都要实例化一次变量是因为变量作用域的缘故。一个方法内部可能存在多个作用域每个作用域都可能包含局部变量的声明而一个 lambda 表达式可以从多个作用域捕获变量给出如下示例代码 其执行结果如下 其中outercounter 变量被两个委托共用而 innerCounter 为画个委托分别所有。每个委托都需要各自的上下文但是各自的上下文还需要指向一个公共的上下文。编译器会为这种情况创建两个私有嵌套类转义后的结果如下 大多数情况很少需要查看这样的代码但编译器生成代码的方式会对程序性能有不小的影响。如果在性能敏感的代码中使用 lambda 表达式那么需要注意可能会因为变量捕获而创建过多对象从而影响性能。
3.5.2 表达式树
lambda 表达式可以由编译器转换成表达式树。表达式树是将代码按照数据来表示的一种形式。这项特性是 LINQ 能够有效处理 SQL 数据库的核心秘诀所在。通过表达式树C# 的代码可以在执行期被分析并转换成 SQL。 委托的作用是提供可运行的代码而表达式树的作用是提供可查看的代码这有点类似于反射机制。虽然也可以在代码中直接构建表达式树但更普遍的做法是让编译器负责把 lambda 表达式转换成表达式树。
以下面的 lambda 表达式为例 编译器并未在任何地方生成一个硬编码的字符串。以上字符串是通过表达式树动态构建出来的。这段代码表明代码是可以进行执行期检查的。这就是表达式树的所有关键所在。
首先看 adder 的类型ExpressionFuncint, int, int。把它拆解成两部分 ExpressionTDelegate 和 Funcint, int, int。Funcint, int, int 是 ExpressionTDelegate 的类型实参它是一个代理类型由两个 int 参数和一个 int 返回值构成。
ExpressionTDelegate是处理 TDelegate 类型的表达式树类型。其中 TDelegate 必须是委托类型。委托类型仅仅是表达式树相关的诸多类型之一它们均位于 Systarn.Linq.Expressions 命名空间下。非泛型的 Expression 类是所有表达式类型的抽象基类。
adder 变量是一个表示接收两个整型值并返回一个整型值方法的表达式树表示之后可以用 lambda 表达式来为该变量赋值。编译器负责生成适用于执行期的表达式树。示例代码如下 转换表达式树的局限性
只有拥有表达式主体的 lambda 表达式才能转换成表达式树。下面这句代码会编译报错 从 .NET 3.5 开始表达式树 API 就已经扩展支持代码块和其他构建了但 C# 编译器依然保留了该限制而且对于 LINQ 使用的表达式树也有同样的限制。这是对象初始化器和集合初始化器很重要的原因可以在一个表达式内完成初始化以供表达式树使用。另外lambda 表达式不能使用赋值运算符也不能使用 C# 4 的动态类型和 C# 5 的异步。
将表达式树编译成委托
表达式树可用于在执行期动态构建委托。这种方式一般需要手动编写部分代码而不是使用 lambda 表达式进行转化。
ExpressionTDelegate 有一个 Compile() 方法该方法返回一个委托类型。该委托类型与普通的委托类型无异。
以上述代码为例构建出 adder 表达式树将其编译成一个委托然后调用该委托并打印出结果 3.6 扩展方法
3.6.1 声明扩展方法
扩展方法必须声明在一个非嵌套、非泛型的静态类中。在 C#7.2 之前箕一个参数不能是 ref 参数。扩展方法所在的类不能是泛型类但扩展方法自身可以是泛型方法。扩展方法的第一个参数有时称为扩展目标或扩展类型。 编译器唯一需要做的就是为扩展方法及其所在类添加Extension特性。该特性在命名空间 System.Runtime.CompilerServices 下。其本质上是一个标记标记 ToInstant() 方法可以按照 DateTimeOffset 的实例方法那样凋用。
3.6.2 调用扩展方法
扩展方法可以在其第一个参数的类型实例上以实例方法的调用方式进行调用但还需要一个前提让编译器可以查找到这个扩展方法。
优先级问题 如果存在一个与该类同名的普通实例方法那么编译器总是会优先选择该实例方法来调用。 在此过程中无所谓扩展方法是否具有更匹配的形参。如果编译器查找到有可调用的实例方法就不会再去查找扩展方法了。 如果编译器没有找到可调用的实例方法那么会开始查找扩展方法。首先查找扩展方法调用代码所在的命名空间以及所有 using 指令指定的命名空间。 编译器会从以下位置查找扩展方法
CSharpInDepth.Chapter03 命名空间下的静态类CSharpInDepth 命名空间下的静态类全局命名空间下的静态类using 指令指定的命名空间下的静态类例如 using System 这样的指向命名空间的命令;只在 C#6 中using static 指定的静态类10.1节还会介绍。
补充
编译器会从最内层的命名空间一路向外查找至全局命名空间。在查找的每条路径上都要查找当前命名空间下的静态类或者查找 using 指令指定的命名空间中的类。查找的顺序并不重要。如果调整 using 指令的顺序后影响了扩展方法的查找结果建议将扩展方法重新命名。查找的每一步中都有可能找到多个适合调用的扩展方法。此时编译器会对当前所有候选方法执行常规的重载决议。在决策完成与编译器为调用扩展方法所生成的 IL 代码和调用普通静态方法所生成的 IL 代码是完全相同的。 说明 x.Method(y); 如果 Method 是实例方法x 为 null就会抛出 NulLReferenceException 而如果 Method 是一个扩展方法那么即便 x 为 null也会将 x 作为其首个参数进行方法调用。 3.6.3 扩展方法的链式调用
下面示例代码是一个简单查询现有一个单词序列按照单词长度进行筛选并将其按字母顺序排序然后全部转换为大写。该查询只用到了 C#3 中的 lambda 表达式和扩展方法这两个特性。 注意以上代码中 Where、OrderBy 和 Select 三个调用的顺序就是操作实际发生的顺序。由于 LINQ 中存在延退和优化策略很难知道具体何时会执行什么操作但代码的阅读顺序和执行顺序是一致的。
下列代码实现了上述相同的查询功能但没有使用扩展方法。 对比之下可以发现明显的缺陷代码阅读起来很困难。代码中方法调用的顺序和实际执行的顺序刚好相反Where 方法是第一个被调用的却放在了末尾。lambda 表达式 word word.ToUpper() 究竟属于哪个方法调用很不明确。它本属于 Select 方法 但和 Select 中间隔了一堆代码。
还有一个解决方法是将每个方法调用的结果都赋给一个局部变量然后通过上一个变量再继续调用下一个方法。但大量额外的局部变量容易造成混淆且会分散注意力。 由上可见方法的链式调用带来的好处不仅仅限于 LINQ。一个方法调用的结果用作另一个方法调用的开始。扩展方法能让我们以可读性强的方式编码任何类型而且不局限于那些已经支持链式调用的类型。
3.7 查询表达式
虽然几乎 C# 3 的所有特性都对 LINQ 有所贡献但只有查询表达式是专门为 LINQ 设计的。 使用查询表达式我们可以通过查询专用语句select, where、let、group by 等编写简洁的查询代码。由编译器负责把查询表达式翻译成非查询语句的形式并进行常规编译。回顾一下 3.6.3 节的代码 使用查询表达式改写的功能相同的查询代码如下所示其中加粗的部分为查询表达式 3.7.1 从 C# 到 C# 的查询表达式转换
语言规范直接将查询表达式定义为一种语法转译且该转译过程发生在绑定或重载决议之前。即查询表达式会首先被编译器转义为可执行的 C# 代码。很多时候转译的结果就是使其变成对应的扩展方法调用不过语言规范并没有强制要求该行为。
3.7.2 范围变量和隐形标识符
查询表达式引入了范围变量的概念。范围变量与普通变量不同范围变量充当了查询语句中每条子句中的输入。
在上一个例子中位于查询表达式起始位置的 from 子句引入了范围变量加粗部分: 子句中引入范围变量的最简单方式应该是使用 let 关键字。假设需要在查询中多次使用单词长度这个变量但又不想每次都调用 Length 属性。如果需要就单词长度进行琲序并且在输出结果中使用长度变量那么使用 let 子句的查询如下所示 在对查询进行转译时该如何表示 length 和 word 呢这需要把原始的单词序列转换成“单词-长度”对。在需要访问范围变量的子句中再通过变量对来访问其中的某个变量 这里的 tmp 不属于查询转译的一部分语言规范中是用 * 符号表示的。在语言规范并没有规定为查询构建表达式树时参数应当使用什么名称。这个名称本身不重要因为在编写查询时它是不可见的因此把它称为隐形标识符。
3.7.3 选择使用哪种 LINQ 语法
查询表达式更适合大规模查询表现出众可读性强。 必须以 from 子句开始以 select 或者 group by 子句结尾。 方法语法更适合简单查询简单明了。
例如 对比采用扩展方法的写法就显得有些笨拙了 说明 对于采用非查询表达式的语法目前没有统一的术语而有方法语法、点式语法、流式语法、lambda 语法等名称之后会统一采用方法语法来代称。 当查询变得更复杂时方法语法依然可以从容应对 LINQ 中提供的很多方法并没有与之对应的查询表达式语法。 例如 Select 和 Where 的某些重载方法返回的是元素以及元素对应的索引值。 如果想在查词的结尾执行一个方法调用例如调用 ToList() 来把结果转换成 ListT 对象就要把整个查询表达式用圆括号括起来 如果使用方法语法只需在末尾直接添加方法调用即可。
在很多情况下包括上述例子在内两种方式难分高下。
3.8 终极形态LINQ
下面介绍 C#3 特性是如何成就 LINQ 的。假设有一个查询从 Entity Framework 获取数据代码如下所示假设已存在某数据库和相应的表结构 短短 4 行代码应用了所有新特性。 匿名类型. 包括投射初始化器只选择 name 和 price 这两个属性。 使用 var 声明的匿名类型. 因为无法声明 products 变量的有效类型。 查询表达式。 当然对于本例可以不使用查询表达式但对于更复杂的情况使用查询表达式能事半功倍。 lambda 表达式。 lambda 表达式在这里作为查询表达式转译之后的结果。 扩展方法。 使得转译后的查询可以通过 Queryable 类实现因为 dbContext.Products 实现了 IQueryableProduct接口。 表达式树。 使得查询逻辑可以按照数据的方式传给 LINQ 提供器然后转换成 SQL 语句并交由数据库执行。 文章转载自: http://www.morning.wrwcf.cn.gov.cn.wrwcf.cn http://www.morning.ypmqy.cn.gov.cn.ypmqy.cn http://www.morning.crxdn.cn.gov.cn.crxdn.cn http://www.morning.bwgrd.cn.gov.cn.bwgrd.cn http://www.morning.dschz.cn.gov.cn.dschz.cn http://www.morning.wfkbk.cn.gov.cn.wfkbk.cn http://www.morning.ppqzb.cn.gov.cn.ppqzb.cn http://www.morning.gcfrt.cn.gov.cn.gcfrt.cn http://www.morning.ylqrc.cn.gov.cn.ylqrc.cn http://www.morning.wqrdx.cn.gov.cn.wqrdx.cn http://www.morning.gynlc.cn.gov.cn.gynlc.cn http://www.morning.pqjpw.cn.gov.cn.pqjpw.cn http://www.morning.zlqyj.cn.gov.cn.zlqyj.cn http://www.morning.kfbth.cn.gov.cn.kfbth.cn http://www.morning.skdhm.cn.gov.cn.skdhm.cn http://www.morning.mfbcs.cn.gov.cn.mfbcs.cn http://www.morning.kcbml.cn.gov.cn.kcbml.cn http://www.morning.ttryd.cn.gov.cn.ttryd.cn http://www.morning.srbl.cn.gov.cn.srbl.cn http://www.morning.dxqfh.cn.gov.cn.dxqfh.cn http://www.morning.dqdss.cn.gov.cn.dqdss.cn http://www.morning.kpypy.cn.gov.cn.kpypy.cn http://www.morning.ptmsk.cn.gov.cn.ptmsk.cn http://www.morning.kgfsz.cn.gov.cn.kgfsz.cn http://www.morning.gcqs.cn.gov.cn.gcqs.cn http://www.morning.mrgby.cn.gov.cn.mrgby.cn http://www.morning.rtjhw.cn.gov.cn.rtjhw.cn http://www.morning.rdxnt.cn.gov.cn.rdxnt.cn http://www.morning.rdkgw.cn.gov.cn.rdkgw.cn http://www.morning.kzrbn.cn.gov.cn.kzrbn.cn http://www.morning.kyzja.com.gov.cn.kyzja.com http://www.morning.rhjsx.cn.gov.cn.rhjsx.cn http://www.morning.jikuxy.com.gov.cn.jikuxy.com http://www.morning.rklgm.cn.gov.cn.rklgm.cn http://www.morning.lnrhk.cn.gov.cn.lnrhk.cn http://www.morning.rkdzm.cn.gov.cn.rkdzm.cn http://www.morning.rjnm.cn.gov.cn.rjnm.cn http://www.morning.nndbz.cn.gov.cn.nndbz.cn http://www.morning.shyqcgw.cn.gov.cn.shyqcgw.cn http://www.morning.ndynz.cn.gov.cn.ndynz.cn http://www.morning.lgtzd.cn.gov.cn.lgtzd.cn http://www.morning.rhph.cn.gov.cn.rhph.cn http://www.morning.djxnn.cn.gov.cn.djxnn.cn http://www.morning.fkmqg.cn.gov.cn.fkmqg.cn http://www.morning.nqgff.cn.gov.cn.nqgff.cn http://www.morning.lbcbq.cn.gov.cn.lbcbq.cn http://www.morning.lhptg.cn.gov.cn.lhptg.cn http://www.morning.hqxyt.cn.gov.cn.hqxyt.cn http://www.morning.gkktj.cn.gov.cn.gkktj.cn http://www.morning.qywfw.cn.gov.cn.qywfw.cn http://www.morning.rnxs.cn.gov.cn.rnxs.cn http://www.morning.qszyd.cn.gov.cn.qszyd.cn http://www.morning.dxzcr.cn.gov.cn.dxzcr.cn http://www.morning.hxrg.cn.gov.cn.hxrg.cn http://www.morning.dbrnl.cn.gov.cn.dbrnl.cn http://www.morning.qpnmd.cn.gov.cn.qpnmd.cn http://www.morning.nlryq.cn.gov.cn.nlryq.cn http://www.morning.nmkbl.cn.gov.cn.nmkbl.cn http://www.morning.gzgwn.cn.gov.cn.gzgwn.cn http://www.morning.dhqg.cn.gov.cn.dhqg.cn http://www.morning.qhmql.cn.gov.cn.qhmql.cn http://www.morning.krnzm.cn.gov.cn.krnzm.cn http://www.morning.npxcc.cn.gov.cn.npxcc.cn http://www.morning.qbwmz.cn.gov.cn.qbwmz.cn http://www.morning.mhlkc.cn.gov.cn.mhlkc.cn http://www.morning.xfhms.cn.gov.cn.xfhms.cn http://www.morning.zsthg.cn.gov.cn.zsthg.cn http://www.morning.xnflx.cn.gov.cn.xnflx.cn http://www.morning.dpsgq.cn.gov.cn.dpsgq.cn http://www.morning.trsmb.cn.gov.cn.trsmb.cn http://www.morning.xbwqg.cn.gov.cn.xbwqg.cn http://www.morning.ytmx.cn.gov.cn.ytmx.cn http://www.morning.wtwhj.cn.gov.cn.wtwhj.cn http://www.morning.fcrw.cn.gov.cn.fcrw.cn http://www.morning.dcmnl.cn.gov.cn.dcmnl.cn http://www.morning.kfbth.cn.gov.cn.kfbth.cn http://www.morning.knwry.cn.gov.cn.knwry.cn http://www.morning.fmrrr.cn.gov.cn.fmrrr.cn http://www.morning.fylsz.cn.gov.cn.fylsz.cn http://www.morning.tqbw.cn.gov.cn.tqbw.cn