前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]

yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]

作者头像
蒋金楠
发布于 2018-01-15 11:06:33
发布于 2018-01-15 11:06:33
1.6K00
代码可运行
举报
文章被收录于专栏:大内老A大内老A
运行总次数:0
代码可运行

昨天写了《yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]》,引起了一些讨论。关于yield关键字这个语法糖背后的原理(C#编译器将它翻译成什么)其实挺简单,虽然有时候因为误用它会导致一些问题,但是它本无过错。接下来,我们通过这篇短文简单地谈谈我所理解的yield。

目录 一、先看一个简单的例子 二、了解本质,只需要看看yield最终编译成什么 三、回到WCF的例子

一、先看一个简单的例子

我们现在看一个简单的例子。我们在一个Console应用中编写了如下一段简单的程序:返回类型为IEnumerable<string>的方法GetItems以yield return的方式返回一个包含三个字符串的集合,而在方法开始的时候我们打印一段文字表明定义在方法中的操作开始执行。在Main方法中,我们先调用GetItems方法将“集合对象”返回,然后调用其ToArray方法。在调用该方法之前我们打印一段文字表明对集合对象进行迭代。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void Main(string[] args)
{
    IEnumerable<string> items = GetItems();
    Console.WriteLine("Begin to iterate the collection.");
    items.ToArray();
}

static IEnumerable<string> GetItems()
{
    Console.WriteLine("Begin to invoke GetItems() method");
    yield return "Foo";
    yield return "Bar";
    yield return "Baz";
}

对于上面这段代码,我想肯定有人会认为得到的结果应该是这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Begin to invoke GetItems() method
Begin to iterate the collection.

但是下面才是真正的执行结果。也就是说,一旦我们在一个返回类型为IEnumerable或者IEnumerable<T>的方式中通过yield return返回集合元素,意味着这个定义在方法中操作会被“延后执行”——操作的真正执行不是发生在方法调用的时候,而是延后到对返回的集合进行迭代的时候。我们大体可以以这样的方式来“解释”这个现象:一旦我们使用了yield return,返回元素的操作会被封装成“可执行的表达式”的方式返回,一旦我们对集合进行迭代的时候,这些表达式才会被执行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Begin to iterate the collection.
Begin to invoke GetItems() method

二、了解本质,只需要看看yield最终编译成什么

上面我们通过“延迟执行”和“可执行表达式”的形式来解释yield return,仅仅是为了比较好地理解它所体现出来的效果而已,实际上并没有这回事,这与LINQ的延迟加载更不是一回事。yield return仅仅是C#的一个语法糖而已,是编译器玩的一个小花招。如何透过这一层“糖纸”看到本质的东西,只需要看看编译器最终编译后的与之等效的代码是什么样子就可以了。对于上面这个例子来说,不管GetItems方法中以何种方式返回需要的对象,返回值总归是一个实现了IEnumerable <string>接口的某个类型的对象,我们只需要看看这个类型具有怎样的定义就知道C#编译器如果来“解释”yield return。

我们可以直接利用Reflector打开编译后的程序集,然后将.NET Framework的版本调成1.0(不支持C#针对后续版本提供的语法糖),这样就可以以“本质”的方式查看我们编写的代码了。如下面的代码片段所示,GetItems方法中没有发现我们定义的代码,而是直接返回一个类型为<GetItems>d__0的对象,看到这里相信读者朋友们知道为什么执行GetItems方法的时候并没有文字输出的真正原因了吧。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
internal class Program
{
    private static IEnumerable<string> GetItems()
    {
        return new <GetItems>d__0(-2);
    }
    private sealed class <GetItems>d__0 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
}

<GetItems>d__0是自动生成的类型,它实现了IEnumerable<string>接口,也实现了IEnumerator<string>,其 GetEnumerator()方法返回的实际上就是他自己。至于对<GetItems>d__0对象的进行迭代的时候如何返回具体元素,只要看看该类型的定义就一目了然了。如下面的代码片段所示,集合元素的返回实现在MoveNext()方法中,方法开始的操作(Console.WriteLine("Begin to invoke GetItems() method"))发生在第一次迭代的时候。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private sealed class <GetItems>d__0 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
{
    private int <>1__state;
    private string <>2__current;

    private bool MoveNext()
    {
        switch (this.<>1__state)
        {
            case 0:
                this.<>1__state = -1;
                Console.WriteLine("Begin to invoke GetItems() method");
                this.<>2__current = "Foo";
                this.<>1__state = 1;
                return true;

            case 1:
                this.<>1__state = -1;
                this.<>2__current = "Bar";
                this.<>1__state = 2;
                return true;

            case 2:
                this.<>1__state = -1;
                this.<>2__current = "Baz";
                this.<>1__state = 3;
                return true;

            case 3:
                this.<>1__state = -1;
                break;
        }
        return false;
    }
    string IEnumerator<string>.Current
    {
        [DebuggerHidden]
        get
        {
            return this.<>2__current;
        }
    }

    object IEnumerator.Current
    {
        [DebuggerHidden]
        get
        {
            return this.<>2__current;
        }
    }
}

三、回到WCF的例子

再次回到《yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]》中提到的例子,现在来解释为什么针对如下两段代码,前者抛出的异常不能被WCF正常处理,而后者可以。原因很简单——两段代码抛出异常的时机是不一样的。对于后者,异常在执行GetItems方法的时候会立即抛出来,WCF会捕获这个异常并作为应用级别的异常进行正常处理;对于前者,通过上面的分析我们知道异常实际上发生在对返回“集合对象”进行迭代的时候。具体是什么时候呢?其实就是对返回对象进行序列化的时候,此时抛出的异常将将会视为系统异常来处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class DemoService : IDemoService
{
    public IEnumerable<string> GetItems(string categoty)
    {
        if (string.IsNullOrEmpty(categoty))
        {
            throw new FaultException("Invalid category");
        }
        yield return "Foo";
        yield return "Bar";
        yield return "Baz";
    }
}

public class DemoService : IDemoService
{
    public IEnumerable<string> GetItems(string categoty)
    {
        if (string.IsNullOrEmpty(categoty))
        {
            throw new FaultException("Invalid category");
        }
        return new string[] { "Foo", "Bar", "Baz" };
    }
}

我个人觉得这是WCF值得改进的地方,但是目前来说为了避免这样的问题,我推荐将WCF契约接口操作方法中的返回类型定义成数组,而不是IEnumerable或者IEnumerable<T>(顺便说一下,WCF针对Array、List以及其他集合类型的序列化/反序列化行为是一致的),但是我个人对IEnumerable或者IEnumerable<T>不排斥。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2013-04-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
NOSQL数据库学习,NoSQL总结(二)
泛指非关系型的数据库,随着互联网Web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别
用户1289394
2022/02/15
2K0
NoSQL之Redis数据库初探
  随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类型的Web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题:
全栈程序员站长
2021/12/29
2740
NoSQL之Redis数据库初探
NoSQL概述
我们现在处理什么年代 2020年 大数据时代 适者生存 学习才是在这个社会生存的唯一法则。
后端码匠
2020/11/06
1K0
NoSQL概述
【Redis】001-NoSQL概述
2020年了,必须精通Spring Boot + Spring Cloud才有竞争力!
訾博ZiBo
2025/01/06
1040
【Redis】001-NoSQL概述
【大话NoSQL】——什么是NoSQL?
开始之前,先说说写这篇博文的背景,本来是想写MongoDB的内容,但是MongoDB又是非关系型数据库中最火的一个。我还是本着自己一直习惯的学习步骤,先有全局观,再着眼于微观,所以有必要先了解一下非关系数据库的发展历史,再开始学习MongoDB。否则,我们学习再多的MongoDB也只能是手中的一把沙,抓的越紧,剩下的越少。
程序猿小亮
2021/01/28
1.2K0
redis | 一、NoSql演进史
在 web 初现峥嵘的那段时间 ,大部分网站都是使用的单机 MySQL 来存储用户数据,由于网站的用户与访问量不会太大,甚至大部分都使用额静态网页,与后端没有过多的交互,所以单机 MySQL 足矣
雨中散步撒哈拉
2022/09/21
4280
关于NoSQL优势的一点想法
想法来源于与刚才龙老大的一番讨论,文中对于NoSQL概念性的东西摘录自:http://www.infoq.com/cn/news/2011/01/nosql-why
libo1106
2018/08/08
4830
Redis超详细总结
在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站不多。
说故事的五公子
2020/05/07
9400
Redis超详细总结
干货 | SQL 与 NoSQL还在傻傻分不清?
上一节我们认识了数据库,了解了数据库事务是什么,索引是如何提升数据库性能的,现在我们来学习下大家常说的一些数据库,MySQL、mongoDB、kv等等这些又有什么区别。本文中,SQL 与 NoSQL 代表关系型数据库与非关系型数据库,当然,SQL ≠ 关系型数据库,这里用作简写。
腾讯NEXT学位
2019/05/16
7020
为什么要使用redis数据库?它有哪些妙用?
redis是Nosql数据库中使用较为广泛的非关系型内存数据库,redis内部是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型,类似于Java中的map)。Redis基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。
Java编程指南
2019/08/05
4.1K0
为什么要使用redis数据库?它有哪些妙用?
NoSql简介
数据库写入压力增加,读写放于一个库中,数据库压力太大。所以采用主从复制。读写分离的思路,减轻服务器负担
石的三次方
2021/01/05
1.2K0
大数据开发:为你详解NoSQL
很多刚入门的小伙伴可能会有疑惑,到底什么是NoSQL,很多人刚开始学习的时候很容易对NoSQL产生误会,其实NoSQL=Not Only SQL,它指的是“不仅仅是SQL”,那么它具体指代的是什么呢,它有哪些方面的特征呢,今天就和大家好好的聊一聊NoSQL。
成都加米谷大数据
2021/03/01
3370
大数据开发:为你详解NoSQL
NoSQL漫谈
NoSQL是指非关系型的数据库,NoSQL(Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库革命性运动,随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS(Social Networking Services,即社会性网络服务)类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。
BUG弄潮儿
2022/06/30
7650
Redis之NoSql入门和概述
后来,随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候, Memcached就自然的成为一个非常时尚的技术产品。
yuanshuai
2022/08/22
3300
Redis之NoSql入门和概述
NoSql数据库,是怎么解决我们高并发场景下MySql表现的不足
通过前面几天的学习,我们在面对高并发流量时,为了应对大量读写请求,特此将我们的普通存储系统开发成了一套分布式存储系统。主要基于读写分离主从复制以及数据分库分表实现的。不清楚的可以再回去看看啊数据库读写分离方案,实现高性能数据库集群,数据库分库分表后,我们生产环境怎么实现不停机数据迁移
架构师修炼
2020/07/17
1.8K0
redis第一章:redis原理,使用背景,下载安装
当时的业务很相对简单,就是JSP—>Action—->Service—->DAO—–>数据库,数据库也就是一个实例而已,无论是Mysql还是Oracle。把这五层缩减为三层的话便是:应用层——>DAO层——>Mysql实例。
全栈程序员站长
2022/08/05
3980
redis第一章:redis原理,使用背景,下载安装
NoSQL初探之人人都爱Redis:(1)Redis简介与简单安装
  随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类型的Web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题:
Edison Zhou
2018/08/20
3470
NoSQL初探之人人都爱Redis:(1)Redis简介与简单安装
后端思维之数据库性能优化方案
毫不夸张的说咱们后端工程师,无论在哪家公司,呆在哪个团队,做哪个系统,遇到的第一个让人头疼的问题绝对是数据库性能问题。如果我们有一套成熟的方法论,能让大家快速、准确的去选择出合适的优化方案,我相信能够快速准备解决咱么日常遇到的80%甚至90%的性能问题。
陈珙
2022/05/10
1.3K1
Redis---NoSQL数据库介绍
1、解决功能性的问题:Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN
大忽悠爱学习
2021/11/15
3620
NoSQL 还是 SQL ?这一篇讲清楚
1.NoSQL的诞生原因 随着互联网快速发展,各种类型的应用层出不穷,所以导致在这个云计算的时代,对技术提出了更多的需求,主要体现在下面这四个方面: 低延迟的读写速度:应用快速地反应能极大地提升用户的满意度; 原因:当数据量达到一定规模时,由于关系型数据库的系统逻辑非常复杂,使得其非常容易发生死锁等的并发问题,所以导致其读写速度下滑非常严重; 支撑海量的数据和流量:对于搜索这样大型应用而言,需要利用PB级别的数据和能应对百万级的流量; 原因:有限的支撑容量:现有关系型解决方案还无法支撑Google这样海量的
大数据和云计算技术
2018/03/08
1.5K0
NoSQL 还是 SQL ?这一篇讲清楚
相关推荐
NOSQL数据库学习,NoSQL总结(二)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文