亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C# yield在WCF中的錯誤使用(二)

2020-01-24 02:00:15
字體:
來源:轉載
供稿:網友

昨天寫了《yield在WCF中的錯誤使用――99%的開發人員都有可能犯的錯誤[上篇]》,引起了一些討論。關于yield關鍵字這個語法糖背后的原理(C#編譯器將它翻譯成什么)其實挺簡單,雖然有時候因為誤用它會導致一些問題,但是它本無過錯。接下來,我們通過這篇短文簡單地談談我所理解的yield。

目錄

一、先看一個簡單的例子
二、了解本質,只需要看看yield最終編譯成什么
三、回到WCF的例子

一、先看一個簡單的例子
我們現在看一個簡單的例子。我們在一個Console應用中編寫了如下一段簡單的程序:返回類型為IEnumerable<string>的方法GetItems以yield return的方式返回一個包含三個字符串的集合,而在方法開始的時候我們打印一段文字表明定義在方法中的操作開始執行。在Main方法中,我們先調用GetItems方法將“集合對象”返回,然后調用其ToArray方法。在調用該方法之前我們打印一段文字表明對集合對象進行迭代。

復制代碼 代碼如下:

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";
}

對于上面這段代碼,我想肯定有人會認為得到的結果應該是這樣:

復制代碼 代碼如下:

Begin to invoke GetItems() method
Begin to iterate the collection.

但是下面才是真正的執行結果。也就是說,一旦我們在一個返回類型為IEnumerable或者IEnumerable<T>的方式中通過yield return返回集合元素,意味著這個定義在方法中操作會被“延后執行”――操作的真正執行不是發生在方法調用的時候,而是延后到對返回的集合進行迭代的時候。我們大體可以以這樣的方式來“解釋”這個現象:一旦我們使用了yield return,返回元素的操作會被封裝成“可執行的表達式”的方式返回,一旦我們對集合進行迭代的時候,這些表達式才會被執行。
復制代碼 代碼如下:

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方法的時候并沒有文字輸出的真正原因了吧。

復制代碼 代碼如下:

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"))發生在第一次迭代的時候。
復制代碼 代碼如下:

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會捕獲這個異常并作為應用級別的異常進行正常處理;對于前者,通過上面的分析我們知道異常實際上發生在對返回“集合對象”進行迭代的時候。具體是什么時候呢?其實就是對返回對象進行序列化的時候,此時拋出的異常將將會視為系統異常來處理。

復制代碼 代碼如下:

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>不排斥。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人免费一级人片100| 国产精品国模在线| 国产欧美日韩精品专区| 日韩中文有码在线视频| 亚洲精品自拍偷拍| 日韩av在线一区| 国产成+人+综合+亚洲欧洲| 91在线免费看网站| 久久久爽爽爽美女图片| 国产精品视频区1| 成人国产精品免费视频| 97视频在线观看网址| 日韩精品中文字幕视频在线| 国产精品成人久久久久| 日韩欧美在线视频日韩欧美在线视频| 亚洲综合色激情五月| 亚洲天堂av综合网| 亚洲精品一区二三区不卡| 91精品国产高清久久久久久久久| 亚洲精品之草原avav久久| 亚洲免费中文字幕| 精品久久久精品| 国产一区二区丝袜| 亚洲女成人图区| 免费97视频在线精品国自产拍| 久久精品在线视频| 激情懂色av一区av二区av| 97精品国产97久久久久久免费| 欧美大尺度激情区在线播放| 日本精品va在线观看| 日韩中文字幕在线视频播放| 成人午夜一级二级三级| 国产精品久久网| 久久久999精品视频| 国产亚洲精品va在线观看| 亚洲一区二区免费在线| 欧洲精品毛片网站| 国产一区玩具在线观看| 欧美男插女视频| 久久综合免费视频| 亚洲精品国产精品久久清纯直播| 国产精品久久久久久久久久久不卡| 久久久999精品免费| 97婷婷涩涩精品一区| 久久久午夜视频| 欧美激情a∨在线视频播放| 国产91精品久久久久| 亚洲精品一区中文| 国产日韩在线一区| 国产精品日韩欧美综合| 日韩在线观看免费全集电视剧网站| 久久天天躁狠狠躁夜夜av| 欧美日韩爱爱视频| 欧美激情亚洲一区| 久久99精品久久久久久噜噜| 丝袜亚洲另类欧美重口| 狠狠躁夜夜躁人人爽天天天天97| 91国内精品久久| 国产热re99久久6国产精品| 精品无码久久久久久国产| 欧美成人合集magnet| 国内精品国产三级国产在线专| 97视频com| 亚洲精品日韩久久久| 亚洲欧美国产精品| 亚洲视频axxx| 色综合久久88色综合天天看泰| 日本精品中文字幕| 日韩美女视频在线观看| 日韩综合视频在线观看| 欧美日本亚洲视频| 日韩av免费在线| 国模精品一区二区三区色天香| 国产精品久久久久久久久久久新郎| 午夜精品久久久久久久男人的天堂| 热久久这里只有| 国产精品欧美亚洲777777| 成人综合国产精品| 亚洲影院高清在线| 不卡av电影在线观看| 国产精品久久久av久久久| 亚洲第一精品久久忘忧草社区| 97精品在线视频| 一本久久综合亚洲鲁鲁| 精品国产一区二区三区四区在线观看| 在线播放日韩精品| 日韩国产欧美区| 最新国产精品拍自在线播放| 欧美一区二区.| 91国产精品91| 欧美日韩成人精品| 国产日韩欧美中文| 亚洲日本aⅴ片在线观看香蕉| 日韩免费看的电影电视剧大全| 久久久噜久噜久久综合| 欧美精品第一页在线播放| 美女视频久久黄| 中文字幕av一区二区| 久久躁日日躁aaaaxxxx| 亚洲美女福利视频网站| 国产精品自拍偷拍| 亚洲欧美中文字幕| 91久久久久久国产精品| www.久久色.com| 7777kkkk成人观看| 国产精品久久久久久久美男| 亚洲精品国偷自产在线99热| 亚洲自拍偷拍色图| 亚洲第一页自拍| 国产精品吊钟奶在线| 久久久久亚洲精品| 中文字幕精品久久| 日韩av影院在线观看| 日韩中文字幕在线看| 国产精品1234| 国产一区二中文字幕在线看| 综合国产在线视频| 日本午夜精品理论片a级appf发布| 国产亚洲精品久久久| 久久精品男人天堂| 欧美精品在线网站| 亚洲欧洲美洲在线综合| 国产精品 欧美在线| 日韩欧美在线视频日韩欧美在线视频| 久久亚洲私人国产精品va| 亚洲国产欧美一区二区三区同亚洲| 亚洲国产成人爱av在线播放| 欧美性猛交xxxx乱大交| 欧美精品18videos性欧美| 久久精品视频99| 欧美高清videos高潮hd| 精品国产户外野外| 最近2019年好看中文字幕视频| 国产日韩精品电影| 日韩成人免费视频| 欧美午夜www高清视频| 久久久久久久久亚洲| 亚洲欧美综合v| 国产精品三级网站| 亚洲一级黄色片| 日韩av网站电影| 久久久久女教师免费一区| 精品亚洲男同gayvideo网站| 国产精品自产拍在线观| 亚洲第一网中文字幕| 亚洲精品少妇网址| 亚洲区在线播放| 性金发美女69hd大尺寸| 久久久电影免费观看完整版| 91久久久久久| 亚洲国产精品成人一区二区| 综合网日日天干夜夜久久| 久久香蕉精品香蕉| 日韩高清av一区二区三区| 国产午夜精品视频免费不卡69堂| 欧美在线观看www| 理论片在线不卡免费观看| 国产91网红主播在线观看| 久久免费在线观看| 精品免费在线视频| 久久久中文字幕| 91夜夜揉人人捏人人添红杏| 国产精品第2页| 九九热最新视频//这里只有精品|