日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转载】SharpDevelop代码分析

發布時間:2025/5/22 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转载】SharpDevelop代码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【原文地址】http://www.cnblogs.com/passos/archive/2004/10/04/48950.html



??? 最近開始學習.Net,遇到了一個比較不錯的開源的IDE SharpDevelop。這個開發工具是使用C#開發的,比較吸引我的一點就是它是采用了和Eclipse類似的插件技術來實現整個系統的。而這個插件系統是我最感興趣的地方,因此開始了一段代碼的研究。在本篇之后,我會陸續把我研究的心得寫下來。由于是在網吧上網,有諸多不便,因此可能會拖比較長的時間。



一、基本概念

??? 首先,我們先來對 SharpDevelop 有一個比較感性的認識。你可以從這里下載到它的可執行程序和代碼包????http://www.icsharpcode.com/? ,安裝的廢話就不說了,先運行一下看看。感覺跟VS很像吧?不過目前的版本是1.0.0.1550,還有很多地方需要完善。關于代碼和系統結構,SharpDevelop的三個作者寫了一本書,各位看官可以參考一下,不過我看過之后還是有很多地方不太理解。

??? 然后,讓我來解釋一下什么叫插件以及為什么要使用插件系統。我們以往的系統,開發人員編譯發布之后,系統就不允許進行更改和擴充了,如果要進行某個功能的擴充,則必須要修改代碼重新編譯發布。這就給我們帶來了比較大的不方便。解決的方法有很多,例如提供配置等等方法。在解決方案之中,插件是一個比較好的解決方法。大家一定知道PhotoShop、WinAmp吧,他們都有“插件”的概念,允許其他開發人員根據系統預定的接口編寫擴展功能(例如PhotoShop中各種各樣的濾鏡)。所謂的插件就是系統的擴展功能模塊,這個模塊是以一個獨立文件的形式出現的,與系統是相對獨立。在系統設計期間并不知道插件的具體功能,僅僅是在系統中為插件留下預定的接口,系統啟動的時候根據插件的配置尋找插件,根據預定的接口把插件掛接到系統中。

??? 這樣的方式帶來什么樣的優點呢?首先是系統的擴展性大大的增強了,如果我們在系統發布后需要對系統進行擴充,不必重新編譯,只需要修改插件就可以了。其次有利與團隊開發,各個功能模塊由于是以插件的形式表現在系統中,系統的每日構造就很簡單了,不會因為某個模塊的錯誤而導致整個系統的BUILD失敗。失敗的僅僅是一個插件而已。

??? PhotoShop和Winamp的插件系統是比較簡單的,他們首先實現了一個基本的系統,然后在這個系統的基礎上掛接其他擴展的功能插件。而SharpDevelop的插件系統更加強大,它的整個系統的基礎就僅僅是一個插件管理系統,而你看到的所有的界面、功能統統都是以插件的形式掛入的。在這樣的一個插件系統下,我們可以不修改基本系統,僅僅使用插件就構造出各種各樣不同的系統。

??? 現在讓我們來看看它的插件系統。進入到SharpDevelop的安裝目錄中,在Bin目錄下的SharpDevelop.exe 和 SharpDevelop.Core.dll是這個系統的基本的插件系統。在Addins目錄下有兩個后綴是addin的文件,其中一個 SharpDevelopCore.addin 就是它的核心插件的定義(配置)文件,里面定義的各個功能模塊存在于Bin\Sharpdevelop.Base.dll 文件中,另外還有很多其他的插件定義在Addins目錄下的addin文件中。

??? 分析SharpDevelop的代碼,首先要弄清楚幾個基本的概念,這些概念和我以前的預想有一些區別,我深入了代碼之后才發現我的困惑所在。

1、AddInTree??插件樹
??? SharpDevelop 中的插件被組織成一棵插件樹結構,樹的結構是通過 Extension(擴展點)中定義的Path(路徑)來定義的,類似一個文件系統的目錄結構。系統中的每一個插件都在配置文件中指定了 Extension,通過Extension中指定的 Path 掛到這棵插件樹上。在系統中可以通過 AddTreeSingleton對象來訪問各個插件,以實現插件之間的互動。

2、?AddIn 插件
??? 在 SharpDevelop 的概念中,插件是包含多個功能模塊的集合(而不是我過去認為的一個功能模塊)。在文件的表現形式上是一個addin配置文件,在系統中對應 AddIn 類。

3、Extension 擴展點
??? SharpDevelop中的每一個插件都會被掛到 AddInTree(插件樹) 中,而具體掛接到這個插件樹的哪個位置,則是由插件的 Extension 對象中的 Path?指定的。在addin 配置文件中,對應于 <Extension> 。例如下面這個功能模塊的配置

<Extension?path?=?"/SharpDevelop/Workbench/Ambiences">
?????????
<Class?id????=?".NET"?class?=?"ICSharpCode.SharpDevelop.Services.NetAmbience"/>
?
</Extension>

指定了擴展點路徑為 /SharpDevelop/Workbench/Ambiences ,也就是在插件樹中的位置。

4、Codon
??? 這個是一個比較不好理解的東西,在 SharpDevelop 的三個作者寫的書的中譯版中被翻譯為密碼子,真是個糟糕的翻譯,可以跟Handle(句柄)有一拼了。詞典中還有一個翻譯叫“基碼”,我覺得這個也不算好,不過還稍微有那么一點意思。(這里我原來誤寫為“代碼子”,在評論中有位仁兄說這個翻譯不錯,現在我覺得也好像確實不錯 ^o^)
??? 根據我對代碼的理解,Codon 的功能是描述(包裝)一個功能模塊(一個功能模塊對應一個實現了具體功能的 Command 類)。為了方便訪問各個插件中的功能模塊, Codon 給各種功能定義了基本的屬性,分別是 ID (功能模塊的標識),Name (功能模塊的類型。別誤會,這個Name 是addin文件定義中Codon的XML結點的名稱,ID才是真正的名稱),其中Name可能是Class(類)、MenuItem(菜單項)、Pad(面板)等等。根據具體的功能模塊,可以繼承Codon定義其他的一些屬性,SharpDevelop中就定義了 ClassCodon、MenuItemCodon、PadCodon等等,你可以根據需要自己定義其他類型的Codon。在addin定義文件中,Codon對應于 <Extension> 標簽下的內容。例如下面這個定義

<Extension?path?=?"/SharpDevelop/Workbench/Ambiences">
?????????
<Class?id????=?".NET"?class?=?"ICSharpCode.SharpDevelop.Services.NetAmbience"/>
?
</Extension>

<Extension ...> 內部定義了一個Codon,<Class ...>? 表示該Codon是一個 Class(類),接著定義了該Codon的?ID和具體實現該Codon的類名ICSharpCode.SharpDevelop.Services.NetAmbience。運行期間將通過反射來找到對應的類并創建出來,這一點也是我們無法在以前的語言中實現的。

再例如這一個定義

?<Extension?path?=?"/SharpDevelop/Views/ProjectBrowser/ContextMenu/CombineBrowserNode">
????????????????
<MenuItem?id?=?"Compile"
??????????????????????????label?
=?"${res:XML.MainMenu.RunMenu.Compile}"?
??????????????????????????class?
=?"ICSharpCode.SharpDevelop.Commands.Compile"/>
????????????????
<MenuItem?id?=?"CompileAll"
??????????????????????????label?
=?"${res:XML.MainMenu.RunMenu.CompileAll}"?
??????????????????????????class?
=?"ICSharpCode.SharpDevelop.Commands.CompileAll"/>
????????????????
<MenuItem?id?=?"CombineBuildGroupSeparator"?label?=?"-"?/>
?.
</Extension>

這個擴展點中定義了三個菜單項,以及各個菜單項的名字、標簽和實現的類名。這里的Codon就對應于系統中的MenuCodon對象。

5、Command 命令
??? 正如前文所述,Codon描述了一個功能模塊,而每個功能模塊都是一個 ICommand 的實現。最基本的 Command 是? AbstractCommand,根據Codon的不同對應了不同的 Command。例如 MenuItemCodon 對應 MenuItemCommand 等等。

6、Service 服務
??? 插件系統中,有一些功能是整個系統都要使用的,例如文件訪問、資源、消息等等。這些功能都作為插件系統的一個基本功能為整個系統提供服務,我們就叫“服務”好了。為了便于訪問,這些服務都統一通過 ServiceManager 來管理。其實服務也是一種類型的插件,它們的擴展點路徑在目錄樹中的 /Workspace/Services 中。

??? 理解了這幾個基本的概念之后,就可以看看 SharpDevelop 的代碼了。從 src\main\startup.cs 看起吧,之后是addin.cs、addinTree.cs?等等。?


二、主程序+隱藏的初始化

?在大學課程里面,我對于模擬電路總是搞不清楚,直到現在也是這樣。我總覺得電路圖很奇怪,總會問“這部分電路是做什么用的”、“為什么會有這樣的效果”。在我的腦海里面,每部分的電路都應該有一定的用處,可是我總是看不明白。我媽媽說,我的思路被軟件所固化的太久了,看電路圖不應該總是一個個模塊的看,正確的方法應該是從電源的一極順著電路看,一直看到電源的另一極。我現在仍然不懂看電路圖,可是以我看代碼的經驗來說,我覺得分析源代碼按照這樣的思路來看會比較容易把脈絡理清楚。
?????在SharpDevelop的代碼中,由于很多的接口和插件的原因,很多代碼在看到某個地方會突然失去函數/方法調用的線索。例如看某個函數的實現的時候會跳到一個接口里面去,那是因為這部分功能在運行期才會給一個實現了這個接口的對象來進行具體的執行。從這個角度來說,設計模式也給我們研究代碼稍微帶來了一點小小的難度。在看Linux下源代碼的時候也經常遇到這種問題,在這個時候尋找代碼線索比較好的方法是用一個文本搜索工具來搜索相關的關鍵字。在Linux下我經常會用grep,Windows下面類似UltraEdit的“批量文件查找”功能會很好用(或者“Search And Replace”之類的工具)。這個是我讀代碼的一點小小的經驗,如果你知道有更好的方法,請告訴我讓我也學習一下 ? 。
?????我不想大段大段的貼代碼出來占地方(空間、帶寬,還有各位看官的注意力),在需要的地方我會貼上主要的代碼,因此最好能夠找代碼來對應著看。把代碼包解壓縮,我把它解到了“F:\SharpDevelop”(如果沒有說明,下文都是以此為代碼的根目錄了)。由于SharpDevelop本身對于察看代碼不是很方便,沒有“轉到定義”之類的功能,因此我建議你把它的代碼轉成VS的工程來看。不過很可惜,SharpDevelop的工程導出功能現在有問題,如果導出\src\SharpDevelop.cmbx 這個總的復合工程的話會失敗(我記得RC1版本是可以成功的,不知道為什么后來的版本反而會出問題),所以只能一個一個工程的導出。
?????好了,讓我們來看SharpDevelop的代碼吧。
1、起點
??? 在主程序的起點在\src\Main\StartUp\SharpDevelopMain.cs,找到Main函數這就是整個程序的起點了。開始的部分是顯示封面窗體并加上命令行控制,其中SplashScreenForm 定義在\src\Main\Base\Gui\Dialogs\SplashScreen.cs文件中,這部分我就不多說了。之后是 Application.ThreadException?+=?new?ThreadExceptionEventHandler(ShowErrorBox);

??? SharpDevelop為了有效的進行錯誤報告,因此自己進行了異常的控制。系統出現異常的時候,SharpDevelop會攔截下來彈出它自己的異常提示報告對話框。這個代碼就是在這一行實現的。其中 ShowErrorBox 這個方法就在類SharpDevelopMain中,ExceptionBox 定義在\src\Main\StartUp\Dialogs\ExceptionBox.cs中。如果需要進行自己的異常控制,可以學習一下這里的技巧。

2、充滿玄機的初始化

string?[]?addInDirs?=?ICSharpCode.SharpDevelop.AddInSettingsHandler.GetAddInDirectories(?out?ignoreDefaultPath?);
AddInTreeSingleton.SetAddInDirectories(addInDirs,?ignoreDefaultPath);

??? 通過AddInSettingsHandler取得插件的目錄,并告知AddInTreeSingleton。AddInSettingsHandler定義在\src\Main\StartUp\Dialogs\AddInTreeSettingsHandler.cs中,它通過讀取系統配置(App.config)文件中的AddInDirectory節點的Path屬性來確定插件的目錄位置,或者你也可以通過自己定義的AddInDirectories節來指定插件目錄。如果你沒有做這些配置,默認的目錄在SharpDevelop運行目錄的..\Addins目錄下。

ServiceManager.Services.AddService(new?MessageService());
ServiceManager.Services.AddService(
new?ResourceService());
ServiceManager.Services.AddService(
new?IconService());

??? 通過ServiceManager(服務管理器)加入三個系統默認的服務,消息服務、資源服務、圖標服務。這三個服務中,消息服務是顯示各種信息提示,另外兩個是屬于系統的資源,SharpDevelop通過服務來進行統一調用和管理。
ServiceManager.Services.InitializeServicesSubsystem("/Workspace/Services");

??? 初始化其他的服務。SharpDevelop把服務定義在插件樹的/Workspace/Services這個路徑中,凡是在這個路徑下的插件都被認為是服務,因此如果你自己定義了一個服務的話,也需要掛到這個路徑下(這里就是系統服務的擴展點了)。

??? 注意!這一步中,在我們的眼皮子底下悄悄的進行了一個重要的初始化工作。各位看官請看,ServiceManager 定義在\src\Main\Core\Services\ ServiceManager.cs文件中,察看它的InitializeServicesSubsystem方法,我們發現這樣一行

AddServices((IService[])AddInTreeSingleton.AddInTree.GetTreeNode(servicesPath).BuildChildItems(this).ToArray(typeof(IService)));

??? 在這里,AddInTreeSingleton首次調用了AddInTree(插件樹)的實例。按照Singleton模式,只有在首次調用的時候才會初始化實例,這里也是同樣如此。整個系統的AddInTree是在這一步中進行了初始化工作,稍候我們將詳細介紹AddInTree如何進行初始化工作,先順便看看服務的初始化。在ServiceManager的InitializeServicesSubsystem方法中,通過AddInTree檢索服務插件路徑下的所有配置,并通過它來讀取、建立具體的對象,然后加入到服務列表中。之后通過一個循環,逐個的調用各個服務的InitializeService方法初始化服務。

??? AddInTree的初始化工作容我們稍候再看,先把主體的代碼看完。

commands = AddInTreeSingleton.AddInTree.GetTreeNode("/Workspace/Autostart").BuildChildItems(null);
for (int i = 0; i < commands.Count - 1; ++i)
{
?((ICommand)commands[i]).Run();
}

??? /Workspace/Autostart是系統自動運行命令的擴展點路徑,定義在這個路徑下的插件會在系統啟動的時候自動運行。在這里,通過插件樹初始化建立處于這個路徑下的Command(命令),并逐一執行。BuildChildItems方法的功能是建立這個擴展點下的Command列表,我會在介紹AddTree的時候具體說明它的實現。

???? 主程序代碼的最后,初始化完畢、關閉封面窗體,然后執行命令列表中最后一個命令(也就是系統的主界面)。在主界面退出的時候,系統卸載所有的服務。

??? 在這部分代碼中,我們知道了兩個系統指定的擴展點路徑 /Workspace/Services 和 /Workspace/Autostart ,我們實現服務和指定系統自動運行命令的時候就可以掛到這兩個擴展點路徑下了。
???? 托反射的福,ServiceManager.Services可以通過類型(接口)來查找具體的實例,也就是GetServices方法。但是ServiceManager的具體實現我們可以容后再看,這里已經不是最緊要的部分了。
???? 接下來,我們來看看整個插件系統的核心-AddinTree的代碼,看看它是如何通過插件配置進行初始化并建立起整個系統的插件樹骨干。

三、插件系統

?? 上回書說到SharpDevelop入口Main函數的結構,ServiceManager.Service在InitializeServicesSubsystem方法中首次調用了AddInTreeSingleton的AddInTree實例,AddInTree在這里進行了初始化。本回進入AddInTree著重講述SharpDevelop的插件系統。在敘述的時候為了方便起見,對于“插件”和插件具體的“功能模塊”這兩個詞不會特別的區分,各位看官可以從上下文分辨具體的含義(而事實上,SharpDevelop中的“插件”是指.addin配置文件,每一個“插件”都可能會包含多個“功能模塊”)。

1、插件的配置
?? 既然說到插件系統,那么我們先來看一看SharpDevelop插件系統的組織形式。
?? 很多時候,同一個事物從不同的角度來看會得出不一樣的結論,SharpDevelop的插件系統也是如此。在看SharpDevelop的代碼以前,按照我對插件的理解,我認為所謂的“插件”就是代表一個功能模塊,插件的配置就是描述該插件并指定如何把這個插件掛到系統中。SharpDevelop中有插件樹的思想,也就是每一個插件在系統中都有一個擴展點的路徑。那么按照我最初對插件的理解,編寫插件需要做的就是:
?? A、根據插件接口編寫功能模塊實現一個Command類
?? B、編寫一個配置文件,指定Command類的擴展點(Extension)路徑,掛到插件樹中

?? 之后按照這樣的理解,我編寫了一個察看插件樹的插件AddinTreeView,打算掛到SharpDevelop中去。根據SharpDevelop對插件的定義,我把具體插件的AddinTreeViewCommand實現了之后,編寫了一個配置文件AddinTreeView.addin如下:

<AddIn?name????????=?"AddinTreeView"
???????author??????
=?"SimonLiu"
???????copyright???
=?"GPL"
???????url?????????
=?"http://www.icsharpcode.net"
???????description?
=?"Display?AddinTree"
???????version?????
=?"1.0.0">

?
<Runtime>
??
<Import?assembly="http://www.cnblogs.com/bin/?AddinTreeView.dll"/>
?
</Runtime>

?
<Extension?path?=?"/SharpDevelop/Workbench/MainMenu/Tools">
??
<MenuItem?id?=?"AddinTreeView"?
???label?
=?"View?AddinTree"?
???class?
=?"Addins.AddinTreeView.AddinTreeViewCommand"/>
?
</Extension>?
</AddIn>


?? 在配置文件中,Runtime節指定了插件功能模塊所在的庫文件Addins.dll的具體路徑,在Extension節中指定了擴展點路徑/SharpDevelop/Workbench/MainMenu/Tools(我是打算把它掛到主菜單的工具菜單下),然后在Extension內指定了它的Codon為 MenuItem以及具體的ID、標簽、Command類名。這樣做,SharpDevelop運行的很不錯,我的插件出現在了Tools菜單下。之后,我又編寫了一個SharpDevelop的資源管理器(ResourceEditor)的插件類ResourceEditor.dll并把它掛到Tool菜單下。同樣的,我也寫了一個ResourceEditor.addin文件來對應。系統工作的很正常。

?? 如果我們對于每一個插件都編寫這樣的一個配置文件,那么插件的庫文件(.dll)、插件配置文件(.addin)是一一對應的。不過這樣就帶來了一個小小的問題,在這樣的一個以插件為基礎的系統中,每一個菜單、工具欄按鈕、窗體、面板都是一個插件,那么我們需要為每一個插件編寫配置文件,這樣就會有很多個配置文件(似乎有點太多了,不是很好管理)。SharpDevelop也想到了這個問題,于是它允許我們把多個插件的配置合并在一個插件的配置文件中。因此,我把我的兩個插件庫文件合并到一個Addins工程內生成了Addins.dll,又重新編寫了我的插件配置文件MyAddins.addin如下:

<AddIn?name????????=?"MyAddins"
???????author??????
=?"SimonLiu"
???????copyright???
=?"GPL"
???????url?????????
=?"http://www.icsharpcode.net"
???????description?
=?"Display?AddinTree"
???????version?????
=?"1.0.0">

?
<Runtime>
??
<Import?assembly="http://www.cnblogs.com/bin/Addins.dll"/>
?
</Runtime>

?
<Extension?path?=?"/SharpDevelop/Workbench/MainMenu/Tools">
??
<MenuItem?id?=?"ResourceEditor"?
???label?
=?"Resource?Editor"?
???class?
=?"Addins.ResourceEditor.Command.ResourceEditorCommand"/>?
??
<MenuItem?id?=?"AddinTreeView"?
???label?
=?"View?AddinTree"?
???class?
=?"Addins.AddinTreeView.AddinTreeViewCommand"/>?
?
</Extension>?
</AddIn>


?? 這樣,我把兩個插件的功能模塊使用一個插件配置文件來進行配置。同樣的,我也可以把幾十個功能模塊合并到一個插件配置文件中。SharpDevelop把這個插件配置文件稱為“Addin(插件)”,而把具體的功能模塊封裝為Codon,使用Command類來包裝具體的功能。SharpDevelop本身的核心配置SharpDevelopCore.addin里面就包含了所有的基本菜單、工具欄、PAD的插件配置。
我們回過頭來看一下,現在我們有了兩顆樹。首先,插件樹本身是一個樹形的結構,這個樹是根據系統所有插件的各個Codon的擴展點路徑構造的,表示了各個Codon在插件樹中的位置,各位看官可以通過我寫的這個小小的AddinTreeView來看看SharpDevelop中實際的結構。其次,插件的配置文件本身也具有了一個樹形的結構,這個樹結構的根節點是系統的各個插件配置文件,其下是根據這個配置文件中的Extension節點的來構成的,描述了每個Extension節點下具有的Codon。我們可以通過SharpDevelop的Tools菜單下的AddinScout來看看這個樹的結構。
我為了試驗,把SharpDevelop的插件精簡了很多,構成了一個簡單的小插件系統。下面是這個精簡系統的兩個樹的截圖。各位看官可以通過這兩副圖理解一下插件樹和插件配置文件的關系(只是看同樣問題的兩個角度,一個是Codon的ExtensionPath,一個是配置文件的內容)。


總結一下SharpDevelop插件的配置文件格式。首先是 <AddIn>節點,需要指定AddIn的名稱、作者之類的屬性。其次,在AddIn節點下的<Runtime>節點內,使用<Import …>來指定本插件配置中Codon所在的庫文件。如果分布在多個庫文件中,可以一一指明。然后,編寫具體功能模塊的配置。每個功能模塊的配置都以擴展點<Extension>開始,指定了路徑(Path)屬性之后,在這個節點內配置在這個擴展點下具體的Codon。每個Codon根據具體不同的實現有不同的屬性。各位看官可以研究一下SharpDevelop的核心配置文件SharpDevelopCore.addin的寫法,相信很容易理解的。

2、插件系統的核心AddIn和AddInTree
?? 前文講到,在SharpDevelop的Main函數中,ServiceManager.Service在InitializeServicesSubsystem方法中首次調用了AddInTreeSingleton的AddInTree實例,AddinTree在這個時候進行了初始化。現在我們就來看看AddInTreeSingleton.AddInTree到底做了些什么事情,它定義在\src\Main\Core\AddIns\AddInTreeSingleton.cs文件中。

???public?static?IAddInTree?AddInTree?
???
{
??????
get?
??????
{
?????????
if?(addInTree?==?null)?
?????????
{
????????????CreateAddInTree();
?????????}

?????????
return?addInTree;
??????}

???}

?? AddInTreeSingleton是插件樹的一個Singleton(具體的可以去看《設計模式》了),AddInTreeSingleton.AddInTree是一個屬性,返回一個IAddinTree接口。這里我注意到一點,AddInTreeSingleton是從DefaultAddInTree繼承下來的。既然它是一個單件模式,包含的方法全部都是靜態方法,沒有實例化的必要,而且外部是通過AddInTree屬性來訪問插件樹,為什么要從DefaultAddInTree繼承呢?這好像沒有什么必要。這也許是重構過程中被遺漏的一個小問題吧。

?? 我們先來看看IAddinTree接口的內容,它定義了這樣的幾個內容:
????? A、屬性ConditionFactory ConditionFactory 返回一個構造條件的工廠類,這里的條件是指插件配置中的條件,我們以后再詳細說明。
????? B、屬性CodonFactory CodonFactory 返回一個構造Codon的工廠類。
????? C、屬性AddInCollection AddIns 返回插件樹的根節點Addin(插件)集合。
????? D、方法IAddInTreeNode GetTreeNode(string path) 根據擴展點路徑(path)返回對應的樹節點
????? E、方法void InsertAddIn(AddIn addIn) 根據AddIn中的擴展點路徑添加一個插件到樹中
????? F、方法void RemoveAddIn(AddIn addIn) 刪除一個插件
????? G、方法Assembly LoadAssembly(string assemblyFile)? 讀入插件中Runtime節的Import指定的Assembly,并構造相應的CodonFactory和CodonFactory類。

?? AddInTreeSingleton在首次調用AddInTree的時候會調用CreateAddInTree方法來進行初始化。CreateAddInTree方法是這樣實現的:

addInTree?=?new?DefaultAddInTree();

????? 初始化插件樹為DefaultAddInTree的實例,這里我感受到了一點重構的痕跡。首先,DefaultAddInTree從名稱上看是默認的插件樹(既然是默認,那么換句話說還可以有其他的插件樹)。但是SharpDevelop并沒有給外部提供使用自定義插件樹的接口(除非我們修改這里的代碼),也就是說這個名稱并不像它本身所暗示的那樣。其次,按照Singleton通常的寫法以及前面提到AddInTreeSingleton是從DefaultAddInTree繼承下來的疑問,我猜想DefaultAddinTree的內容本來是在AddinTreeSingleton里面實現的,后來也許為了代碼的條理性,把實現IAddinTree內容的代碼剝離了出去,形成了DefaultAddinTree類。至于繼承DefaultAddInTree的問題,也許這里本來是一個AddInTree的基類。這是題外話,也未加證實,各位看官可以不必放在心上(有興趣的可以去找找以前SharpDevelop的老版本的代碼來看看)。
這里有兩個察看代碼的線路,一個是DefaultAddInTree的構造函數的代碼,在這個構造函數中構造了Codon和Condtion的工廠類。另外一個是CreateAddInTree后面的代碼,搜索插件文件,并根據插件文件進行AddIn的構造。各位看官可以選擇走分支線路,也可以選擇先看主線(不過這樣你會漏掉不少內容)。

2.1 支線 (DefaultAddInTree的構造函數)
?? 我們把CreateAddInTree的代碼中斷一下壓棧先,跳到DefaultAddInTree的構造函數中去看一看。DefaultAddInTree定義在\src\Main\Core\AddIns\DefaultAddInTree.cs文件中。在DefaultAddInTree的構造函數中,注意到它具有一個修飾符internal,也就是說這個類只允許Core這個程序集中的類對DefaultAddInTree進行實例化(真狠啊)。構造函數中的代碼只有一句:

?LoadCodonsAndConditions(Assembly.GetExecutingAssembly());

?? 雖然只有一行代碼,不過這里所包含的內容卻很精巧,是全局的關鍵,要講清楚我可有得寫了。首先,通過全局的Assembly對象取得入口程序的Assembly,傳入LoadCodonsAndConditions方法中。在該方法中,枚舉傳入的Assembly中的所有數據類型。如果不是抽象的,并且是AbstractCodon的子類,并且具有對應的CodonNameAttribute屬性信息,那么就根據這個類的名稱建立一個對應的CodonBuilder并它加入CodonFactory中(之后對Condition也進行了同樣的操作,我們專注來看Codon部分,Condition跟Codon基本上是一樣的)。
?? 這里的CodonFactory類和CodonBuilder類構成了SharpDevelop插件系統靈活的基礎,各位看官可要看仔細了。
?? 我們以實例來演示,以前文我編寫的AddinTreeViewCommand為例。在入口的Assembly中會搜索到MenuItemCodon,它是AbstractCodon的一個子類、包裝MenuItem(菜單項)Command(命令)的Codon。符合條件,執行

codonFactory.AddCodonBuilder(new?CodonBuilder(type.FullName,?assembly));

?? 首先根據類名MenuItemCodon和assembly 構造CodonBuilder。CodonBuilder定義在\src\Main\Core\AddIns\Codons\CodonBuilder.cs文件中。在CodonBuilder的構造函數中根據MenuItemCodon的CodonNameAttribute屬性信息取得該Codon的名稱MenuItem。CodonNameAttribute描述了Codon的名稱,這個MenuItem也就是在.addin配置文件中對應的<MenuItem>標簽,后文會看到它的重要用途。在CodonBuilder中除了包含了該Codon的ClassName(類名)和CodonName屬性之外,就只有一個方法BuildCodon了。

??public?ICodon?BuildCodon(AddIn?addIn)
??
{
???ICodon?codon;
???
try?{
????
//?create?instance?(ignore?case)
????codon?=?(ICodon)assembly.CreateInstance(ClassName,?true);
????
????
//?set?default?values
????codon.AddIn?=?addIn;
???}
?catch?(Exception)?{
????codon?
=?null;
???}

???
return?codon;
??}


?? 很明顯,BuildCodon根據構造函數中傳入的assembly和類型的ClassName,建立了具體的Codon的實例,并和具體的AddIn關聯起來。
?? 之后,codonFactory調用AddCodonBuilder方法把這個CodonBuilder加入它的Builder集合中。我們向上一層,看看codonFactory如何使用這個CodonBuilder。
?? 在文件\src\Main\Core\AddIns\Codons\CodonFactory.cs中,codonFactory只有兩個方法。AddCodonBuilder方法把CodonBuilder加入一個以CodonName為索引的Hashtable中。另外一個方法很重要:

??public?ICodon?CreateCodon(AddIn?addIn,?XmlNode?codonNode)
??
{
???CodonBuilder?builder?
=?codonHashtable[codonNode.Name]?as?CodonBuilder;
???
???
if?(builder?!=?null)?{
????
return?builder.BuildCodon(addIn);
???}

???
???
throw?new?CodonNotFoundException(String.Format("no?codon?builder?found?for?<{0}>",?codonNode.Name));
??}

?? 在這里,addin是這個配置文件的描述(也就是插件),而這個XmlNode類型的CodonNode是什么東西?
?? 還記得配置文件中在<Extension>標簽下的<Class>、<MenuItem>、<Pad>之類的標簽嗎?我曾經說過,這些就是Codon的描述,現在我們來看看到底是不是如此。以前文的AddinTreeView配置為例:

?<Extension?path?=?"/SharpDevelop/Workbench/MainMenu/Tools">
??
<MenuItem?id?=?"AddinTreeView"?
???label?
=?"View?AddinTree"?
???class?
=?"Addins.AddinTreeView.AddinTreeViewCommand"/>?
?
</Extension>?

?? SharpDevelop在讀入插件配置文件的<Extension>標簽之后,就把它的ChildNodes(XmlElement的屬性)依次傳入CodonFactory的CreateCodon方法中。這里它的ChildNodes[0]就是這里的<MenuItem id = ..... />節點,也就是codonNode參數了。這個XML節點的Name是MenuItem,因此CreateCodon的第一行

CodonBuilder?builder?=?codonHashtable[codonNode.Name]?as?CodonBuilder;

?? 根據節點的名稱(MenuItem)查找對應的CodonBuilder。記得前面的CodonBuilder根據CodonNameAttribute取得了MenuItemCodon的CodonName嗎?就是這個MenuItem了。CodonFactory找到了對應的MenuItemCodon的CodonBuilder(這個是在DefaultAddInTree的構造函數中調用LoadCodonsAndConditions方法建立并加入CodonFactory中的,還記得么?),之后使用這個CodonBuilder建立了對應的Codon,并把它返回給調用者。
?? 就這樣,通過CodonNameAttribute,SharpDevelop把addin配置文件的<MenuItem>節點、CodonBulder、MenuItemCodon三部分串起來形成了一個構造Codon的路線。

?? 我們回過頭來整理一下思路,SharpDevelop進行了下面這樣幾步工作:
????? A、建立各個Codon,使用CodonNameAttribute指明它在配置節點中的名稱
????? B、DefaultAddInTree的構造函數中調用LoadCodonsAndConditions方法,搜索所有的Codon,根據Codon的CodonNameAttribute建立對應的CodonBuilder加入CodonFactory中。
????? C、讀取配置文件,在<Extension>標簽下遍歷所有的節點,根據節點的Name使用CodonFactory建立對應的Codon。
?? 其中,Codon的CodonNameAttribute、CodonBuilder的CodonName以及<Extension>標簽下XML節點的Name是一致的。對于Condition(條件)的處理也是一樣。
?? 抱歉,我上網不是很方便也不太會在Blog里面貼圖(都是為了省事的借口^o^),否則也許更好理解這里的脈絡關系。

?? 好了,看到這里,我們看看SharpDevelop中插件的靈活性是如何體現的。首先,addin配置中的Extension節點下的Codon節點名稱并沒有在代碼中和具體的Codon類聯系起來,而是通過CodonNameAttribute跟Codon聯系起來。這樣做的好處是,SharpDevelop的Codon和XML的標簽一樣具有無限的擴展能力。假設我們要自己定義一個Codon類SplashFormCodon作用是指定某個窗體作為系統啟動時的封面窗體。要做的工作很簡單:首先,在SplashFormCodon中使用CodonNameAttribute指定CodonName為Splash,并且在SplashFormCodon中定義自己需要的屬性。然后,在addin配置文件使用<Splash>標簽這樣寫:

??????<Extension?path?=?"/SharpDevelop/?">
????????????
<Splash?id?=?"MySplashForm"?class?=?"MySplashFormClass"/>?
??????
</Extension>

?? 是不是很簡單?另外,對于Condition(條件)的處理也是一樣,也就是說我們也可以使用類似的方法靈活的加入自己定義的條件。

?? 這里我有個小小的疑問:不知道我對于設計模式的理解是不是有點小問題,我感覺CodonBuilder類的實現似乎并不如它的類名所暗示的是《設計模式》中的Builder模式,反而似乎應該是Proxy模式,因此我覺得改叫做CodonProxy是不是比較容易理解?各位看官覺得呢?
?? 另外,雖然稍微麻煩了一小點,不過我覺得配置如果這樣寫會讓我們比較容易和代碼中具體的類關聯起來:

??????<Extension?path?=?"/SharpDevelop/?">
????????????
<Codon?name=”Splash”?id?=?"MySplashForm"?class?=?"MySplashFormClass"/>?
??????
</Extension>


2.2 主線 (AddInTreeSingleton. CreateAddInTree)
?? 啊~我寫的有點累了。不過還是讓我們繼續AddInTreeSingleton中CreateAddInTree的代碼。
?? 在建立了DefaultAddInTree的實例后,AddInTreeSingleton在插件目錄中搜索后綴為.addin的文件。還記得在SharpDevelop的Main函數中曾經調用過AddInTreeSingleton. SetAddInDirectories嗎,就是搜索這個傳入的目錄。看來SharpDevelop把在插件目錄中所有后綴為.addin的文件都看做是插件了。

FileUtilityService?fileUtilityService?=?(FileUtilityService)ServiceManager.Services.GetService(typeof(FileUtilityService));

?? 先學習一下如何從ServiceManager取得所需要的服務,在SharpDevelop中要取得一個服務全部都是通過這種方式取得的。調用GetService傳入要獲取的服務類的類型作為參數,返回一個IService接口,之后轉換成需要的服務。

?? 搜索插件目錄找到一個addin文件后,調用InsertAddIns把這個addin文件中的配置加入到目錄樹中。

static?StringCollection?InsertAddIns(StringCollection?addInFiles)
??
{
???StringCollection?retryList??
=?new?StringCollection();
???
???
foreach?(string?addInFile?in?addInFiles)?{
????AddIn?addIn?
=?new?AddIn();
????
try?{
?????addIn.Initialize(addInFile);
?????addInTree.InsertAddIn(addIn);
????}
?catch?(CodonNotFoundException)?{
?????retryList.Add(addInFile);
????}
?catch?(ConditionNotFoundException)?{
?????retryList.Add(addInFile);
????}
?catch?(Exception?e)?{
?????
throw?new?AddInInitializeException(addInFile,?e);
????}
?
???}

???
???
return?retryList;
??}

?? InsertAddIns建立一個對應的AddIn(插件),調用AddInTree的InsertAddIn方法把它掛到插件樹中。在這里有一個小小的處理,由于是通過Assembly查找和插件配置中Codon的標簽對應的類,而Codon類所在的Assembly是通過Import標簽導入的。因此在查找配置中某個Codon標簽對應的Codon類的時候,也許Codon類所在的文件是在其他的addin文件中Import的。這個時候在前面支線中講到CodonFactory中查找CodonBuilder會失敗,因此必須等到Codon類所在的addin處理之后才能正確的找到CodonBuilder。這是一個依賴關系的處理問題。
?? SharpDevelop在這里處理的比較簡單,調用InsertAddIns方法的時候,凡是出現CodonNotFoundException的時候,都加入一個retryList列表中返回。在CreateAddinTree處理完所有的addin文件之后,再重新循環嘗試處理retryList列表中的addin。如果某次循環中再也無法成功的加入retryList中的addin,那么才提示失敗錯誤。

?? 我們回頭來看看對AddIn的處理。

2.2.1? addIn.Initialize (AddIn的初始化)
?? 建立了AddIn的實例后,調用Initialize 方法進行初始化。AddIn是對一個.addin文件的封裝,定義在\src\Main\Core\AddIns\AddIn.cs文件中。其中包含了.addin文件的根元素<AddIn>的描述,包括名稱、作者、版權之類的屬性。在<AddIn>節點下包括兩種節點:一個是<Runtime>節點,包含了<Import>指定要導入的Assembly;另外一個是<Extension>節點,指定Codon的擴展點。在AddIn.Initialize方法中,使用XmlDocument對象來讀取對應的addin文件。首先讀取name、author 、copyright之類的基本屬性,之后遍歷所有的ChildNodes(子節點)。

?? 如果子節點是Runtime節點,則調用AddRuntimeLibraries方法。

???foreach?(object?o?in?el.ChildNodes)?
???
{
??????XmlElement?curEl?
=?(XmlElement)o;

??????
string?assemblyName?=?curEl.Attributes["assembly"].InnerText;
??????
string?pathName?????=?Path.IsPathRooted(assemblyName)???assemblyName?:?fileUtilityService.GetDirectoryNameWithSeparator(path)?+?assemblyName;
??????Assembly?asm?
=?AddInTreeSingleton.AddInTree.LoadAssembly(pathName);
??????RuntimeLibraries[assemblyName]?
=?asm;
???}

?? 通過AddInTreeSingleton.AddInTree.LoadAssembly方法把Assembly中所有的Codon和Condition的子類加入對應Factory類中(調用了LoadCodonsAndConditions方法,我們在DefaultAddInTree的構造函數中見過了),并且把該文件和對應的Assembly保存到RuntimeLibraries列表中。

?? 如果子節點是Extension節點,則調用AddExtensions方法。

??????Extension?e?=?new?Extension(el.Attributes["path"].InnerText);
??????AddCodonsToExtension(e,?el,?
new?ConditionCollection());
??????extensions.Add(e);

?? 根據這個擴展點的XML描述建立Extension對象加入到AddIn的Extensions列表中,并通過AddCodonsToExtension方法把其中包括的Codon加入到建立的Extension對象中。Extension對象是AddIn的一個內嵌類,其中一個重要的屬性就是CodonCollection這個列表。AddCodonsToExtension就是把在配置中出現的Codon都加入到這個列表中保存。

?? 來看看AddCodonsToExtension方法。在代碼中我略過了對Condition(條件)的處理的分析和一些無關緊要的部分,我們把注意力集中在插件的處理。首先是一個 foreach (object o in el.ChildNodes) 遍歷<Extension>下所有的子節點,對于每個子節點的處理如下:

??????XmlElement?curEl?=?(XmlElement)o;
??????
switch?(curEl.Name)
??????
{
??????(對條件的處理)
??????
default:
?????????ICodon?codon?
=?AddInTreeSingleton.AddInTree.CodonFactory.CreateCodon(this,?curEl);
?????????AutoInitializeAttributes(codon,?curEl);

?????????(對codon.InsertAfter?和codon.InsertBefore?的處理,主要是處理codon在列表中的順序問題,這一點在對于MenuItemCodon的處理上比較重要)

?????????e.CodonCollection.Add(codon);
?????????
if?(curEl.ChildNodes.Count?>?0)?
?????????
{
????????????Extension?newExtension?
=?new?Extension(e.Path?+?'/'?+?codon.ID);
????????????AddCodonsToExtension(newExtension,?curEl,?conditions);
????????????extensions.Add(newExtension);
?????????}

?????????
break;
???}


?? 我們看到了一個期待已久的調用

AddInTreeSingleton.AddInTree.CodonFactory.CreateCodon(this,?curEl);

?? 經過了上文支線2.1代碼中的鋪墊,SharpDevelop使用建立好的CodonFactory,調用CreateCodon方法根據<Extension>下的節點構造出實際的Codon對象,一切盡在不言中了吧。
?? e.CodonCollection.Add(codon);把構造出來的Codon對象加入到Extension對象的CodonCollection列表中。
?? 之后,在形如菜單的這種允許無限嵌套的結構中,SharpDevelop對此進行了處理。如果該節點有嵌套的子節點,那么構造一個新的Extension對象,遞歸調用AddCodonsToExtension添加到這個Extension對象中。注意一點,這個新構造的Extension對象并不是分開保存在Codon中,而是直接保存在AddIn的擴展點列表中。這樣是為了方便查找,畢竟保存在具體的Codon中也沒有什么用處,我們可以通過Extension對象的Path屬性得知它在插件樹中的具體位置。

2.2.2 addInTree.InsertAddIn(把AddIn添加到AddInTree中)
?? 對AddIn的構造完成之后,需要把AddIn的實例對象添加AddInTree中管理。

??????addIns.Add(addIn);
??????
foreach?(AddIn.Extension?extension?in?addIn.Extensions)
??????
{
?????????AddExtensions(extension);
??????}

?? 在DefaultAddInTree中,保存了兩課樹。一個是根據插件文件的結構形成的樹,每個插件文件作為根節點,往下依次是Extension、Codon節點。addIns.Add(addIn);就是把插件加入到這個樹結構中。另外一個樹是根據Extension的Path+Codon的ID作為路徑構造出來的,每一個樹節點是一個AddInTreeNode類,包含了在這個路徑上的Codon對象。嵌套在這個節點中的Codon在通過它子節點來訪問。在DefaultAddInTree中可以通過GetTreeNode來指定一個路徑獲得插件樹上某一個節點的內容。
?? AddExtensions方法很簡單,遍歷Extension中所有的Codon,把Extension的Path+Codon的ID作為路徑,創建這個路徑上的所有節點,并把Codon連接到這個AddInTreeNode上。由于Codon的ID是全局唯一的,因此每一個AddInTreeNode都具有一個唯一的Codon。

3、最后一公里(Codon和Command的關聯)
?? 在插件樹的討論中,我們依次把AddIn-Extension-Codon的配置和他們對應的類關聯了起來。不過我們一直沒有涉及到Codon和它包含的Command是如何關聯的。由于這個關聯調用是在插件樹外部的(記得在講述SharpDevelop程序入口Main函數中,提到ServiceManager的方法InitializeServicesSubsystem么?AddServices((IService[])AddInTreeSingleton.AddInTree.GetTreeNode(servicesPath).BuildChildItems(this).ToArray(typeof(IService))); 這里就調用了BuildChildItems),因此單獨在這里說明。實現這個關聯的就是AddInTreeNode的BuildChildItems和BuildChildItem方法以及Codon的BuildItem方法。
?? BuildChildItem方法和BuildChildItems方法僅有一字之差,BuildChildItem是根據指定的Codon的ID在所屬AddInTreeNode的子節點下查找包含該Codon的節點并調用該Codon的BuildItem方法;而BuildChildItems則是首先遍歷所屬AddInTreeNode的所有子節點,依次調用各個子節點的Codon的BuildItem方法,之后再調用所屬AddInTreeNode的Codon的BuildItem方法(也就是一個樹的后根遍歷)。
?? 重點在Codon的BuildItem方法。在AbstractCodon中,這個方法是一個抽象方法,SharpDevelop的代碼注釋中并沒有明確說清楚這個方法是做什么用的。但是我們可以找一個Codon的實例來看看。例如ClassCodon的BuildItem:

??????public?override?object?BuildItem(object?owner,?ArrayList?subItems,?ConditionCollection?conditions)
??????
{
?????????System.Diagnostics.Debug.Assert(Class?
!=?null?&&?Class.Length?>?0);
?????????
return?AddIn.CreateObject(Class);
??????}

?? 調用AddIn的CreateObject,傳入Codon的Class(類名)作為參數,建立這個類的實例。例如這個配置

???<Extension?path?=?"/Workspace/Autostart">
??????
<Class?id?=?"InitializeWorkbenchCommand"?
??????????class?
=?"ICSharpCode.SharpDevelop.Commands.InitializeWorkbenchCommand"/>
???
</Extension>

?? 而Codon的中的Class(類名)屬性就是ICSharpCode.SharpDevelop.Commands.InitializeWorkbenchCommand。也就是說,Codon的Class指的是實現具體功能模塊的Command類的名稱。在讀取addin配置中的<Runtime>節的時候,AddInTree把Assembly保存到了RuntimeLibraries中,因此CreateObject方法可以通過它們來查找并建立類的實例。
?? 各位看官可以再看看MenuItemCodon的實現,同樣是建立了對應的SdMenuCommand。
?? 這樣,SharpDevelop本身的插件結構可以和具體的對象建立分離開來,實際的對象建立是在各個Codon的BuildItem中進行的。因此我們可以發現在SharpDevelop整個是基礎插件系統部分沒有任何GUI的操作,實現了很好的解耦效果。

4、問題
?? 好了,本文對插件樹構造的分析到此告一段落。我提一個小小的問題給各位看官思考:在構造插件樹的過程中,如果Codon的某一個節點路徑不存在(也就是說它的依賴項不存在),那么SharpDevelop會提示失敗并且終止程序運行。可是實際上可能因為部署的原因或者權限的原因,某些Codon的失敗并不會影響整個系統的使用,例如試用版本僅僅提供部分插件給客戶使用,而并不希望系統因此而終止運行。那么就存在一個Codon依賴項失敗而允許繼續運行的問題。另外,我希望各個插件不在系統啟動的時候全部調入系統,而是在運行期實際調用的時候才調入系統,也就是一個緩存機制,這樣就可以實現系統插件的熱部署。如何修改SharpDevelop的插件系統來實現這兩個功能呢?

轉載于:https://www.cnblogs.com/sea_peak/archive/2011/04/08/2009910.html

總結

以上是生活随笔為你收集整理的【转载】SharpDevelop代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

久久亚洲在线 | 国产中文字幕国产 | 精品国产乱码久久久久久1区2匹 | 一级做a视频| 在线观看亚洲a | 国产专区在线视频 | 亚洲黄色在线 | 国产欧美精品一区二区三区 | 亚洲免费在线视频 | 日韩欧美网址 | 天天艹天天 | 一级a毛片高清视频 | 国产精品免费观看国产网曝瓜 | 国产91区 | 久影院| 中文字幕人成人 | 99精品国产aⅴ | 亚洲在线网址 | 超级碰碰碰视频 | 人人草在线视频 | 免费网址你懂的 | 亚洲精品在线观 | 91免费黄视频 | 中文字幕日本特黄aa毛片 | 欧美极度另类性三渗透 | 97精品视频在线 | 国产亚洲精品久久久久久久久久久久 | 人人草人人草 | 国产精品毛片久久 | 97精品国产91久久久久久久 | 久久9999久久免费精品国产 | 麻豆视频免费观看 | 99久久一区 | 五月婷婷六月综合 | 久久情侣偷拍 | 国产999精品久久久影片官网 | 国产精品一码二码三码在线 | 色综合天天射 | 国产精品久久久久毛片大屁完整版 | 欧美a级成人淫片免费看 | 中文字幕在线看人 | 丁香综合激情 | 91超碰免费在线 | 久久人人97超碰国产公开结果 | 欧美作爱视频 | 日本中文字幕在线观看 | 亚洲一区精品二人人爽久久 | 波多野结衣一区二区 | 国产精选在线观看 | 夜夜躁狠狠燥 | 国产在线传媒 | 国产探花 | 久久久免费看 | 国产成人精品av久久 | 日韩av区| 男女精品久久 | 99精品在线免费在线观看 | 色多多视频在线 | 狠狠色噜噜狠狠狠狠 | 综合色中色 | 久久久综合电影 | 欧美日韩精品免费观看 | 九九在线视频免费观看 | 国产福利小视频在线 | 国产精在线 | 亚洲五月六月 | 成人一区二区在线观看 | 久草电影在线 | 中文字幕一区二区在线播放 | 91免费日韩 | 国产在线观看高清视频 | 日日碰狠狠添天天爽超碰97久久 | 国产视频一区二区在线播放 | 久久狠狠婷婷 | 久草精品视频在线看网站免费 | 日本久久不卡视频 | 国产精品永久久久久久久www | 日韩免费成人 | 亚洲国产中文在线观看 | 国产精品视频你懂的 | 国产剧情在线一区 | 亚洲人xxx| 久草在线资源观看 | 免费在线观看日韩视频 | 波多野结衣精品 | 中文字幕在线观看你懂的 | 久久综合精品国产一区二区三区 | 国产a精品 | www.五月婷 | 国产资源精品在线观看 | 97视频免费观看2区 亚洲视屏 | 九九热国产 | 婷婷丁香狠狠爱 | 日韩免费久久 | 超碰个人在线 | 日韩草比 | 午夜91视频 | 亚洲一区二区黄色 | 夜夜操综合网 | 亚洲作爱视频 | 人人爽久久涩噜噜噜网站 | 午夜视频不卡 | 久草视频首页 | 嫩草av影院| 久久久福利视频 | 亚洲做受高潮欧美裸体 | 国产精品成人免费精品自在线观看 | 夜夜看av | 美女网站黄在线观看 | 天天激情天天干 | 久久成人视屏 | 国产精品久久久久久久婷婷 | 91成人精品一区在线播放69 | 久爱综合 | 日日天天干 | 久久国产精品精品国产色婷婷 | avwww在线观看 | 国产 av 日韩 | 一区二区视频免费在线观看 | 99久久精品一区二区成人 | 国产91精品久久久久 | 人人看人人 | 久一在线 | 中文字幕在线观看免费 | 久久一区91| 狠狠干婷婷 | 五月天中文字幕 | 美女视频是黄的免费观看 | 少妇自拍av | 日韩欧美视频在线 | 91九色在线 | 美女视频免费精品 | 日韩在线视频一区二区三区 | 国产成人一区二区三区电影 | 免费一级特黄毛大片 | 国产1区2区3区在线 亚洲自拍偷拍色图 | 99国内精品久久久久久久 | 在线视频精品 | 波多野结衣在线观看一区二区三区 | 免费毛片aaaaaa | 毛片888| 狠狠操欧美| 91高清在线 | 国产二区av| 国产精品久久久久毛片大屁完整版 | 日韩精品网址 | 免费观看日韩 | 中文在线字幕免费观看 | 九九视频精品免费 | 免费在线观看的av网站 | 成年人视频在线 | 99在线精品观看 | 丁香激情婷婷 | 色婷婷88av视频一二三区 | 丁香激情五月婷婷 | 日本69hd| 视频在线观看日韩 | 亚洲精品国产精品乱码在线观看 | 成人天堂网 | 成人午夜电影在线观看 | 免费日韩一区二区三区 | 欧美一区二区三区在线观看 | 欧美乱码精品一区二区 | 中文字幕av免费观看 | 在线免费高清视频 | 久久久久黄色 | 狠狠狠狠狠狠干 | 亚洲最新在线 | 精品国产1区二区 | 黄色免费观看网址 | 国产午夜三级一区二区三 | 99久久婷婷国产 | 六月丁香久久 | 国产一区二区在线精品 | 超碰免费av| 亚洲精品中文在线观看 | 国产精品福利午夜在线观看 | 欧美中文字幕久久 | 2024av| 成人av免费在线观看 | 在线亚洲观看 | 波多野结衣精品 | 久操久 | 99爱爱 | 中文字幕麻豆 | 91粉色视频 | 亚洲影视资源 | 亚洲一区av| 一区二区激情视频 | 97国产一区二区 | 91探花在线视频 | 久久久综合香蕉尹人综合网 | 成人一区二区三区在线 | 中文在线免费视频 | 精品久久久久久综合日本 | 成人av片在线观看 | 国产成人av一区二区三区在线观看 | 又黄又爽又无遮挡的视频 | 日本mv大片欧洲mv大片 | 91精品视频导航 | 中文字幕av影院 | 欧美日韩高清一区二区 国产亚洲免费看 | 96亚洲精品久久 | 日韩在线电影 | 日本在线中文在线 | 国产999精品久久久久久麻豆 | 亚洲国产成人精品在线观看 | 国产在线播放一区二区三区 | 久草久热 | 国产69久久久 | 中文字幕一区二区三区在线视频 | 久艹在线观看视频 | 四虎在线观看 | 九九热在线观看 | 91香蕉国产 | av一区在线播放 | 久久全国免费视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 免费福利视频网站 | 中文字幕 二区 | 色无五月 | 色av网站| 天天色草 | 亚洲高清在线视频 | 久久国产精品免费 | 欧美精品久久久久久久久老牛影院 | 免费观看全黄做爰大片国产 | 九九精品视频在线 | 很黄很黄的网站免费的 | 久久狠狠亚洲综合 | 日本精油按摩3 | 日韩中文字幕免费视频 | 3d黄动漫免费看 | 免费瑟瑟网站 | 这里有精品在线视频 | 91亚洲精| 免费网站在线 | 三级免费黄 | 五月天久久婷婷 | 国产精品久久久久久久久搜平片 | 97超碰网 | 在线免费av网 | 中国黄色一级大片 | 在线免费观看麻豆视频 | 久草免费在线视频观看 | 国产欧美最新羞羞视频在线观看 | 中文字幕免费不卡视频 | 国产一区二区三区在线 | 亚洲精品美女久久久 | 久久男人影院 | 日韩美精品视频 | 日p在线观看 | 日韩免费专区 | 人人澡人人干 | 亚洲精品久久视频 | av免费看在线 | 久久久 精品 | 亚洲少妇天堂 | 在线看一区| 婷婷在线不卡 | 日韩欧美国产免费播放 | 欧美精品在线观看一区 | 亚洲综合色视频在线观看 | 久久精品电影网 | 韩日精品在线观看 | 久久久久久久久久久成人 | 国产黄色在线观看 | 在线免费观看黄色 | 免费日韩视频 | 国产一区二区在线观看免费 | 808电影| 国产视频一区在线免费观看 | 国产原创av在线 | 黄色最新网址 | 日韩久久精品一区 | 中文字幕av免费在线观看 | 成人av片在线观看 | 亚洲精品成人 | 精品国产电影一区 | av大片网址 | 日韩欧美视频一区 | 国产一区二区久久久久 | 亚洲精品美女在线观看 | 亚洲欧洲精品一区二区精品久久久 | 欧美一级高清片 | 91看片一区二区三区 | 国产一级做a爱片久久毛片a | 久av在线| 亚洲国产av精品毛片鲁大师 | 久久一线| 超碰最新网址 | 久久精品免费 | 日本久久久影视 | 国产高清不卡 | 最近免费中文字幕 | 国产精品mv在线观看 | 精品欧美一区二区精品久久 | 久久综合久久综合这里只有精品 | 国产黄a三级三级三级三级三级 | 欧美日韩中文在线观看 | 人人超在线公开视频 | 99视频国产精品 | 99久久99久久精品 | 国产亚洲视频在线观看 | 成人在线超碰 | 亚洲精品影院在线观看 | jizz欧美性9 国产一区高清在线观看 | 波多野结衣视频一区 | 久久成人一区 | 在线观看色网站 | 一本一本久久a久久精品牛牛影视 | 人人干天天干 | 成人av电影在线观看 | 欧美老人xxxx18 | 婷婷久久久久 | 国产69精品久久99的直播节目 | 欧美 亚洲 另类 激情 另类 | 丁香电影小说免费视频观看 | 日韩av手机在线观看 | 欧美日韩免费一区二区 | 9热精品| 国产自产在线视频 | 美女福利视频在线 | 91九色九色| 亚洲精品美女免费 | 国产精品一区免费观看 | 国产成人精品999在线观看 | 国产精品一区免费在线观看 | 日韩中文字幕在线 | 就要色综合 | 久久一区二区三区日韩 | av看片网址 | 国产一区二区在线精品 | 黄色特一级片 | 国产视频不卡 | 亚洲激情小视频 | 黄色www | 日韩久久激情 | 久草精品在线观看 | 91久久国产自产拍夜夜嗨 | 91tv国产成人福利 | 狠狠干.com | 国产高清视频网 | 久草网站在线观看 | 92中文资源在线 | 久久久亚洲国产精品麻豆综合天堂 | 在线观看免费成人av | 91av视频免费观看 | 亚洲精品国精品久久99热一 | 中文字幕专区高清在线观看 | 日韩美女久久 | av黄在线播放 | 欧美一级片免费在线观看 | 337p日本欧洲亚洲大胆裸体艺术 | av先锋中文字幕 | 久久久久久国产精品 | 蜜臀av夜夜澡人人爽人人 | 日韩午夜在线 | 久久久久久久电影 | 国产视频一 | 最近中文字幕高清字幕在线视频 | 91在线视频| 最近中文字幕mv | 亚洲欧美乱综合图片区小说区 | 美女网站在线看 | 91香蕉视频黄色 | 中文字幕国产精品 | 亚洲精品短视频 | 精品二区视频 | 人人澡人人干 | 在线看片91 | 69中文字幕| 精品久久久久国产免费第一页 | 看国产黄色大片 | 婷婷久月 | 国产在线观看免 | 国产专区在线播放 | 中文字幕高清免费日韩视频在线 | www.888av| 国产精品一区二区久久久 | 日韩av成人在线观看 | 欧美福利视频 | 在线观看视频一区二区三区 | 亚洲精品1234区 | 国产精品国产自产拍高清av | 久久成人国产精品一区二区 | 樱空桃av | 探花视频在线观看 | 国产精品 日韩精品 | 久久99精品热在线观看 | 亚洲成人黄色在线观看 | 久久99九九99精品 | 中文字幕xxxx | 欧美一级激情 | 波多野结衣视频一区二区 | 亚洲国产一区在线观看 | 欧美激情视频一二区 | 久久久久久国产精品免费 | 日韩色中色 | 中文字幕在线观看av | 中文字幕文字幕一区二区 | 最近的中文字幕大全免费版 | 久久不射电影院 | 亚洲成人资源在线观看 | 久久高清精品 | 国产一级二级在线观看 | 日韩成人免费在线观看 | 狠狠狠色丁香婷婷综合激情 | 久久成人福利 | 最近能播放的中文字幕 | 亚洲电影av在线 | 日女人免费视频 | 最新日韩在线 | 粉嫩一二三区 | 一级免费av | 91网免费观看 | 国产亚洲精品日韩在线tv黄 | 国产精品永久在线观看 | 99视频在线精品免费观看2 | 久久日韩精品 | 黄色.com| 最新影院 | 免费视频 三区 | 国产精品第二页 | 激情丁香 | 国产成人在线网站 | 亚洲成人影音 | 91久久黄色 | 国产精品久久99精品毛片三a | 国产日产欧美在线观看 | 97精品一区 | 国语对白少妇爽91 | 亚洲婷婷在线 | 日韩欧美国产精品 | 亚洲女欲精品久久久久久久18 | 国产精品久久久久久久av大片 | 九九九热精品免费视频观看网站 | 人人爽人人澡 | 国产精品久久久久久久99 | 97超碰免费在线 | 激情视频一区二区 | 久久婷婷国产色一区二区三区 | 亚洲精品黄色在线观看 | 国产精品一区二区在线播放 | 国产亚洲久久 | 欧美日韩免费一区二区三区 | 亚洲成人av片 | 一区二区 不卡 | 中文字幕网站视频在线 | 久久不卡日韩美女 | 日韩免费视频播放 | 日韩精品一区二区三区免费观看视频 | 欧美色图另类 | av黄色在线观看 | 久久69av| 欧美精品视 | 色97在线| 一区二区精品 | 久久久综合电影 | 久久男人中文字幕资源站 | 午夜av电影院 | 狠狠狠色丁香婷婷综合激情 | 日韩女同一区二区三区在线观看 | 天堂av网在线 | 久草在线播放视频 | 日韩一区二区三区免费视频 | 国产精品麻豆欧美日韩ww | 免费看三级网站 | 欧美综合色在线图区 | 在线精品视频免费观看 | 日产av在线播放 | 人交video另类hd | 99国内精品 | 免费黄在线观看 | 亚洲91网站 | 超碰97人 | 国产99久久久国产精品 | 免费人成网ww44kk44 | 日日摸日日爽 | 四虎成人免费影院 | 99精品视频播放 | 天天综合区 | 免费精品视频在线观看 | 波多野结衣视频一区 | 国产精品一区二区三区99 | 色九九影院 | 久久av网| 九九视频在线播放 | 国内久久精品 | 免费看的黄网站软件 | 日韩网站中文字幕 | 成人午夜电影免费在线观看 | 黄色大全免费网站 | 亚洲1级片 | av视屏在线播放 | 久久亚洲私人国产精品 | 91久久一区二区 | 婷婷六月综合网 | 国产伦精品一区二区三区四区视频 | www免费看片com| 在线小视频 | 久久人人爽人人片 | 国产日韩中文在线 | 久久手机免费观看 | 中文字幕 国产视频 | 免费高清在线视频一区· | 国产一级一片免费播放放a 一区二区三区国产欧美 | 国产日韩欧美视频 | 国产 日韩 欧美 自拍 | 免费三级骚 | 九九热免费精品视频 | 高清av免费看 | 人人插人人草 | 手机色站 | 国产免费av一区二区三区 | 婷婷色站 | 97在线视频网站 | 亚洲成人999 | 亚洲专区视频在线观看 | 久久精品99国产精品 | 一区二区视频在线观看免费 | 人人澡人人添人人爽一区二区 | 免费国产一区二区视频 | 精品国产自在精品国产精野外直播 | 日av免费 | av高清免费 | 国产香蕉97碰碰碰视频在线观看 | 91激情视频在线播放 | 国产在线欧美日韩 | 久草热久草视频 | 久久色网站 | 97综合在线 | 在线观看黄色国产 | 欧美日韩精品在线 | 亚洲精品午夜久久久久久久久久久 | 麻豆国产网站入口 | 精品毛片久久久久久 | 精品嫩模福利一区二区蜜臀 | 免费日韩av电影 | 高清久久久 | 免费在线观看午夜视频 | 日韩免费观看视频 | 丝袜美腿一区 | 久久综合九色综合欧美就去吻 | 久久精品视频在线观看免费 | 国产精品久久久久久久久久了 | 综合在线亚洲 | 婷婷www | 视频一区在线播放 | 成人观看 | 欧美性色综合 | 97在线观看免费高清 | 欧美性成人 | 永久免费在线 | 亚洲精品高清在线观看 | 久久黄色免费 | 亚洲在线资源 | 久久国产精品久久精品 | 亚洲欧美视频在线播放 | 黄色片网站av | 久久国语 | 免费在线播放 | 天天操天天干天天摸 | 亚洲 成人 一区 | 欧美一区,二区 | 97超级碰 | 日韩av在线资源 | 日韩免费高清在线 | 97视频亚洲| 粉嫩高清一区二区三区 | 亚州精品天堂中文字幕 | 中文字幕一区二区三区四区在线视频 | 黄色小视频在线观看免费 | 九九免费在线观看视频 | 最近更新好看的中文字幕 | 97超碰资源站 | 香蕉蜜桃视频 | 国产精品不卡在线播放 | 日韩成人精品一区二区三区 | 天天干天天射天天爽 | 中文字幕在线观看国产 | 欧美日本不卡 | 亚洲天堂精品视频 | 日韩精品在线免费观看 | 国产 日韩 在线 亚洲 字幕 中文 | 美女视频黄是免费的 | 偷拍精品一区二区三区 | 日日干夜夜草 | 狠狠干 狠狠操 | 日韩精品视频在线观看免费 | 中文字字幕在线 | 在线成人短视频 | 久久激情电影 | 国产精品一区久久久久 | 99视频网站 | 亚洲成av人片在线观看香蕉 | 亚洲精品国精品久久99热 | 97超碰在线久草超碰在线观看 | 丁香六月网| 日韩视频中文字幕 | 99999精品视频 | 一区二区三区免费在线播放 | 色婷婷av国产精品 | 亚洲最快最全在线视频 | 亚洲欧美日韩一级 | av在线成人| 97超碰国产精品 | 国产精品久久久久久久久久妇女 | 四虎在线视频 | 插综合网| 99久久99视频只有精品 | 亚洲视频免费在线 | av不卡在线看 | 国产高清视频在线观看 | 色综合久久久久网 | 成人免费大片黄在线播放 | 免费亚洲视频在线观看 | 青青河边草免费直播 | 欧美精品免费在线观看 | 人人草在线视频 | 黄色网大全 | 国产精品专区在线 | 午夜精品电影 | 久久精品在线免费观看 | 国产区精品视频 | 亚洲精品456在线播放乱码 | 国产男女免费完整视频 | 在线观看免费视频 | 欧美午夜剧场 | 色姑娘综合天天 | av日韩av| 日韩城人在线 | 精品国产一二三四区 | 亚洲天天综合网 | av大片网址 | 久草在线久草在线2 | 中文字幕在线播出 | 久久婷婷亚洲 | 日韩精品在线看 | 少妇bbbb | 在线观看第一页 | 久在线观看 | 婷婷丁香激情 | 在线观看av不卡 | 久久狠狠一本精品综合网 | 激情久久影院 | 毛片网在线播放 | www.国产毛片 | 欧美日韩综合在线观看 | 亚洲黄色免费网站 | 日韩午夜在线播放 | 免费观看v片在线观看 | 亚洲特级毛片 | 综合婷婷 | 高清不卡毛片 | 亚洲人成人99网站 | 欧美一区二区三区四区夜夜大片 | 久久久久久久久久网站 | www.在线观看av| 久久99亚洲精品久久久久 | 又爽又黄又无遮挡网站动态图 | 国内精品视频在线 | 国产精品视频免费观看 | 欧美在线视频日韩 | 精品在线观看视频 | 一级α片免费看 | 亚洲欧美日本国产 | 日日干,天天干 | 亚洲综合欧美激情 | 国产资源在线免费观看 | 日本中文字幕在线免费观看 | 国产区久久 | 国产精品国产三级国产aⅴ9色 | 九九九热 | 久草电影在线观看 | 99久久精品久久久久久动态片 | 亚洲成av人片在线观看www | 中文字幕av全部资源www中文字幕在线观看 | 超碰人人射 | 日产乱码一二三区别在线 | 国产精品亚洲综合久久 | 国产激情小视频在线观看 | 中文字幕电影一区 | 黄a网站| 精品福利网站 | 国产精品成人一区二区三区吃奶 | 奇米网777 | 久久夜色精品国产欧美乱极品 | 西西4444www大胆无视频 | 国产视频1 | 日韩美女黄色片 | 蜜臀av夜夜澡人人爽人人 | 毛片永久免费 | 日韩在线观看网址 | 在线亚洲午夜片av大片 | 日韩欧美高清一区二区 | 国产亚洲欧洲 | 99视屏| 国内精品视频一区二区三区八戒 | 久久99热久久99精品 | 亚洲最大成人免费网站 | 中文字幕文字幕一区二区 | 国产伦精品一区二区三区免费 | 在线性视频日韩欧美 | 有码视频在线观看 | 日韩欧美视频免费在线观看 | 国产精品久久久久久久电影 | 国产麻豆视频在线观看 | 久草综合在线 | 亚洲少妇激情 | 亚洲另类在线视频 | 精品中文字幕视频 | 久久免费视频精品 | 精品免费一区二区三区 | 亚洲不卡123| 久久黄页| 97成人精品 | 国产精品一区二区三区99 | 成人免费电影 | 久久久久亚洲a | av3级在线| 东方av在 | 天天射天天干天天爽 | 青草视频在线 | 免费成视频 | 亚洲精品在线观看的 | 精品久久一区二区三区 | 欧美视频二区 | 91在线观看欧美日韩 | 国产在线精品国自产拍影院 | 亚洲精品理论片 | 亚洲精品国产精品乱码不99热 | 国产精品久久久久三级 | 国产99久久久国产精品免费二区 | 欧美日韩在线视频免费 | 日韩xxxbbb | 日本性久久 | 中文字幕色在线视频 | 国产日韩精品一区二区三区 | 欧美一区二区在线免费观看 | 91久久奴性调教 | 国内视频在线观看 | 国产成人精品av在线 | 日韩av网站在线播放 | 日韩av一区二区三区 | 亚洲精品成人av在线 | 国产一区在线观看免费 | 黄色性av| 日本性生活一级片 | 亚洲成人黄色 | 一本一道久久a久久精品蜜桃 | 一级黄色片网站 | 国产精品二区在线观看 | 亚洲永久av| 九色91av | 一区二区视频在线免费观看 | 中文字幕国产在线 | 精品视频免费看 | a在线观看免费视频 | 久久久久看片 | 91视频 - 88av| 国产精品男女视频 | 色网站中文字幕 | 亚洲综合最新在线 | 黄色视屏在线免费观看 | 免费视频成人 | 色网站在线看 | 九九欧美视频 | 中文字幕在线观看播放 | 美女黄频在线观看 | 九九九热精品免费视频观看 | 国产日产高清dvd碟片 | 精品二区视频 | 日韩免费在线观看视频 | 伊人中文在线 | 日韩av伦理片 | 日韩欧美高清一区二区三区 | 午夜精品一区二区三区视频免费看 | 婷婷丁香激情网 | 国产精品va在线观看入 | 在线观看免费福利 | av综合站| 国产精品网站一区二区三区 | 国产精品尤物视频 | 久草在线在线视频 | 久久精品视频99 | 97视频在线观看免费 | 亚洲一区二区三区四区在线视频 | 99精品视频在线观看视频 | 91麻豆精品久久久久久 | 天天干天天操天天搞 | 91精品国产综合久久婷婷香蕉 | 国产精品久久久网站 | 丁香网五月天 | 午夜视频一区二区 | www.99在线观看 | 成人在线视频网 | 国产香蕉97碰碰碰视频在线观看 | 国产美女精品视频 | 国产精品黄色影片导航在线观看 | 欧美久久久久久久久久久久久 | 欧美尹人| 精品在线播放 | 五月婷婷丁香网 | 欧美日韩亚洲在线观看 | 超碰人人射 | 中文字幕在线看视频 | 国产亚洲精品成人av久久ww | 91热| 欧美黑人性猛交 | 国产97视频在线 | 欧美日韩高清国产 | www亚洲精品 | 久久久久久久久久影视 | 亚洲国产日韩在线 | 久久综合日| 久久精品国产99国产 | 成人教育av | 国产精品免费小视频 | 国产91在线观看 | 国产一区二区三区四区大秀 | 人人澡超碰碰97碰碰碰软件 | 黄色免费国产 | 91欧美在线 | 亚洲国产婷婷 | 日韩一区二区在线免费观看 | 日韩区在线观看 | 欧美日韩中文视频 | 999久久久免费精品国产 | a午夜在线 | 久久ww| www久久精品 | 一本—道久久a久久精品蜜桃 | 高清av免费看 | 亚洲精品视频在线看 | 午夜精品成人一区二区三区 | 激情视频在线观看网址 | 97品白浆高清久久久久久 | 久久久久久久国产精品视频 | 日本公乱妇视频 | 蜜桃av人人夜夜澡人人爽 | www.天天干.com| 精品久久一二三区 | 在线免费黄 | 国产一区欧美日韩 | 98久久| 97超碰色偷偷 | 日韩免费在线 | 国产精品成人免费精品自在线观看 | 日韩电影中文字幕 | 精品xxx| 久久人网 | 亚洲精品资源在线观看 | 久久久wwww| 九九欧美视频 | 在线观看黄av | 99热99re6国产在线播放 | 国产精品粉嫩 | 18女毛片 | 欧美精品久久久久久久 | 996久久国产精品线观看 | 国产69精品久久久久久久久久 | 国产视频精选 | 在线观看中文字幕第一页 | 久久久久99精品成人片三人毛片 | 狠狠干狠狠艹 | 免费视频色 | 午夜私人影院久久久久 | 国产一级视屏 | 日韩电影久久 | 丁香五香天综合情 | 亚洲精品乱码久久久久久蜜桃91 | 亚洲91精品在线观看 | 在线色亚洲 | 日韩欧美综合在线视频 | 日韩精品免费在线 | 亚洲欧美激情精品一区二区 | 免费看高清毛片 | 亚洲欧美偷拍另类 | 亚洲视频h | 丁香在线视频 | 久久精品小视频 | av在线等| 国产精品美女视频 | 亚洲午夜久久久综合37日本 | 综合天天色 | 日韩免费一区二区 | 欧美日韩在线免费视频 | 国产精品国产亚洲精品看不卡15 | 成人黄色大片在线免费观看 | av电影免费在线播放 | 9幺看片| 亚洲传媒在线 | 在线导航av | 日日操日日插 | 亚洲一区 av | 五月天亚洲精品 | 亚洲电影黄色 | 国产黄色大片免费看 | 91精品视频观看 | 成人在线观看资源 | 午夜视频久久久 | 成年人毛片在线观看 | 亚洲黄色小说网 | 一级片视频在线 | 亚洲综合视频在线 | 久久久免费 | 99精品免费 | 在线电影a| 天天操人人干 | 一区二区三区日韩精品 | 成年人黄色免费看 | 中文av网 | 可以免费看av | 麻豆视频免费网站 | 亚洲va韩国va欧美va精四季 | 国产v在线播放 | 国产精品丝袜久久久久久久不卡 | 日韩欧美精选 | 久久人人爽人人爽人人 | 久久久久久久久久久免费视频 | 免费看的黄色 | 色多多视频在线观看 | 欧美极度另类性三渗透 | 日本资源中文字幕在线 | 激情综合网色播五月 | 9ⅰ精品久久久久久久久中文字幕 | 久久综合久久伊人 | 韩国精品视频在线观看 | 国产精品美女免费看 | 成 人 黄 色视频免费播放 | 亚洲 欧美日韩 国产 中文 | 日韩高清精品一区二区 | 黄色一级影院 | 日日夜夜艹 | 玖玖玖国产精品 | 色婷婷综合久久久中文字幕 | 欧美一区二区免费在线观看 | 国产露脸91国语对白 | 91正在播放 | 国产精品嫩草影院9 | 999精品网| 久久久免费国产 | 久久tv| 国产午夜影院 | 综合久色| 97自拍超碰 | 欧美日韩亚洲在线观看 | 国产99久久久国产精品免费二区 | 天天干夜夜 | 91大片网站 | 亚洲激情 欧美激情 | 玖玖视频国产 | 亚洲自拍自偷 | 天天爱天天操天天射 | 亚洲视频在线看 | 亚洲欧洲精品久久 | 国产网红在线 | 色综合在| 超碰资源在线 | 808电影免费观看三年 | 中文字幕乱偷在线 | www.狠狠操.com | 日韩激情视频 | 午夜精品一区二区三区四区 | 亚州视频在线 | 亚洲在线视频观看 | 亚洲激情综合网 | 黄色在线观看网站 | 久草视频在线播放 | 久久超碰在线 | 国产中文自拍 | 又黄又刺激的网站 | 激情图片区 | 国产午夜精品一区二区三区欧美 | 久久y | 黄色网大全 | bbbb操bbbb| 国产精品99在线观看 | 国产精品久久久久久超碰 | 中国一级片在线观看 | 国产中文字幕在线观看 | 99久久日韩精品视频免费在线观看 | 97人人澡人人添人人爽超碰 | se视频网址 | 欧美人体xx | 国产在线精品观看 | 婷婷综合| 中文字幕在线观看av | 黄色国产高清 | 欧美性猛片, | 成人久久久久久久久久 | 成人在线视频免费看 | 免费在线观看av | 超碰在线成人 | 国产高清视频免费最新在线 | 免费色网站 | 国产性xxxx|