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

首頁 > 編程 > C++ > 正文

在C++中反射調用.NET的方法(三)

2020-05-23 13:53:06
字體:
來源:轉載
供稿:網友

在.NET與C++之間傳輸集合數據

上一篇《在C++中反射調用.NET(二)》中,我們嘗試了反射調用一個返回DTO對象的.NET方法,今天來看看如何在.NET與C++之間傳輸集合數據。

使用非泛型集合的委托方法

先看看.NET類中的一個返回列表數據的方法:

//返回List或者數組,不影響 C++調用 public List<IUserInfo> GetUsers(string likeName) { List<IUserInfo> users = new List<NetLib.IUserInfo>(); for (int i = 0; i < 10; i++) { IUserInfo userinfo = GetUserByID(i); userinfo.Name += likeName; users.Add(userinfo); } //return users.ToArray(); return users; } public IUserInfo GetUserByID(int userId) { IUserInfo userinfo= EntityBuilder.CreateEntity<IUserInfo>(); userinfo.ID = userId; userinfo.Name = "姓名_" + userId; userinfo.Birthday = new DateTime(1980, 1, 1); return userinfo; }

該方法沒有什么復雜業務邏輯,就是將傳遞進來的參數給DTO對象,創建包含10個這樣的對象的列表并返回而已。

對于 GetUsers方法,我們可以創建下面的委托方法來綁定:

Func<String, IEnumerable> fun;

注意這里使用的是非泛型的 IEnumerable接口,在C++需要使用下面這個命名空間:

using namespace System::Collections;

那么為何不能使用泛型集合呢?

using namespace System::Collections::Generic;

因為在C++端,沒有直接引用用戶項目的.NET程序集,并不知道泛型集合類型的具體類型,IUserInfo這個接口無法直接訪問,好在IEnumerable<T>也是繼承 IEnumerable 的,所以可以當做非泛型對象在C++中訪問,因此創建上面的委托方法是可行的。

C++中的列表對象list

下面看看完整的C++/CLI反射調用的代碼:

 std::list<CppUserInfo> GetUsers(String^ likeName) { //調用.NET方法,得到結果 MethodInfo^ method = dotnetObject->GetType()->GetMethod("GetUsers", BindingFlags::Public | BindingFlags::Instance); Func<String^, IEnumerable^>^ fun = (Func<String^, IEnumerable^>^)Delegate::CreateDelegate(Func<String^, IEnumerable^>::typeid,  this->dotnetObject, method); IEnumerable^ result = fun(likeName); std::list<CppUserInfo> cppResult; for each (Object^ item in result) { Func<String^, Object^>^ entityProp = EntityHelper::EntityCallDelegate(item); CppUserInfo user; user.ID = (int)entityProp("ID"); user.Name = (String^)entityProp("Name"); user.Birthday = Convert2CppDateTime((DateTime^)entityProp("Birthday")); cppResult.push_back(user); } return cppResult; }

在C++中,常常使用 list來表示一個列表數據,例如上面方法中的代碼:

std::list<CppUserInfo> cppResult;

為此C++需要包含以下頭文件:

#include <list>

 要將一個對象添加到列表結尾,像下面這樣調用即可:

cppResult.push_back(user);

在上一篇中已經講述了如何從.NET對象轉換給C++本地結構體,所以這個轉換代碼可以直接拿來用,綜合起來,要從.NET集合得到C++的列表對象,像下面這樣使用:

std::list<CppUserInfo> cppResult; for each (Object^ item in result) { Func<String^, Object^>^ entityProp = EntityHelper::EntityCallDelegate(item); CppUserInfo user; user.ID = (int)entityProp("ID"); user.Name = (String^)entityProp("Name"); user.Birthday = Convert2CppDateTime((DateTime^)entityProp("Birthday")); cppResult.push_back(user); }

 C++傳遞集合數據給.NET

前面講了從.NET反射調用獲得一個集合,看起來比較容易,但是從C++反射調用時候傳遞一個集合就不容易了。注意,這里傳遞的還是.NET的集合,所以這里需要做3件事情:

1,首先構建一個.NET集合對象;

2,轉換C++本機結構數據到.NET集合元素;

3,反射調用.NET方法,傳遞數據過去。

先看要反射調用的.NET方法定義:

 public bool SaveUsers(IList<IUserInfo> users) { UserDb.AddRange(users); return true; }

方法非常簡單,沒有什么業務邏輯,接受一個列表接口的數據,然后返回一個布爾值。

在C++端看來,SaveUsers方法的參數對象是一個泛型集合,但是具體是什么對象并不知道,所以需要反射出泛型集合的類型,同時還需要構建這樣一個泛型集合對象實例。

在本例中,要得到IUserInfo 這個泛型集合的類型,可以通過下面的代碼:

MethodInfo^ method = dotnetObject->GetType()->GetMethod("SaveUsers", BindingFlags::Public | BindingFlags::Instance);array<ParameterInfo^>^ pars = method->GetParameters();Type^ paraType= pars[0]->ParameterType;Type^ interfaceType = paraType->GetGenericArguments()[0];

注意上面的代碼中使用了C++/CLI的數組類型 array<Type^>^ ,而不是C++標準庫的數組,因此不要引用下面的命名空間:

using namespace std;

否則VS會提示數組定義缺少參數。

創建泛型List實例

我們使用List來做集合對象,在C#中,我們可以通過下面的方式得到List泛型的類型,然后進一步創建泛型對象實例:

Type t= typeof(List<>);

但是,對應的C++/CLI寫法卻無法通過編譯:

Type^ t=List<>::typeid;

VS總是提示List缺少類型參數,不過像下面這樣子是可以的:

Type^ t2= List<IUserInfo>::typeid;

但是IUserInfo 類型正是我們要動態反射的,事先并不知道,所以一時不知道在C++/CLI中如何構建List泛型的具體實例,MS你不能這么坑好么?

既然無法直接解決,只好曲線救國了,通過類型名字,來創建類型:

 String^ listTypeName = System::String::Format("System.Collections.Generic.List`1[{0}]", interfaceType->FullName);

可惜,這種方式不成功,只好一步步來了,先創建基本的List泛型類型:

 String^ listTypeName = "System.Collections.Generic.List`1"; Type^ listType = System::Type::GetType(listTypeName);

成功,在此基礎上,創建真正的泛型List對象實例就可以了,完整代碼如下:

static Type^ CreateGenericListType(Type^ interfaceType) { //直接這樣創建泛型List不成功: // String^ listTypeName = System::String::Format("System.Collections.Generic.List`1[{0}]", interfaceType->FullName); String^ listTypeName = "System.Collections.Generic.List`1"; Type^ listType = System::Type::GetType(listTypeName); Type^ generListType = listType->MakeGenericType(interfaceType); return generListType; } static IList^ CreateGenericList(Type^ interfaceType) { Type^ generListType = CreateGenericListType(interfaceType); Object^ listObj = System::Activator::CreateInstance(generListType, nullptr); IList^ realList = (IList^)listObj; return realList; }

在方法 CreateGenericListType得到只是一個泛型List的類型,但我們并不知道這個List具體的形參類型,所以這個泛型List還是無法直接使用,幸好,泛型List也是繼承自非泛型的IList接口的,所以在 CreateGenericList 方法中將泛型List對象轉換成IList接口對象,之后就可以愉快的使用List對象了。

IList^ realList = CreateGenericList(interfaceType);

realList->Add(CurrEntity);//CurrEntity 是interfaceType 類型的動態實體類

反射靜態方法

在上一篇中,我們在一個.NET方法中通過接口動態創建實體類,用的是下面的方式:

IUserInfo userinfo= EntityBuilder.CreateEntity<IUserInfo>();

CreateEntity是EntityBuilder的靜態方法,現在我們需要在C++/CLI中,反射調用此方法。

為什么要反射創建實體類?

因為CreateGenericList(interfaceType) 創建的是一個泛型List對象,要求它的成員是一個實體類。

Object^ CreateEntityFromInterface(Type^ interfaceType) {  MethodInfo^ method = this->entityBuilderType->GetMethod("CreateEntity", BindingFlags::Public | BindingFlags::Static);  MethodInfo^ genMethod = method->MakeGenericMethod(interfaceType);  Object^ entity = genMethod->Invoke(nullptr, nullptr);  this->CurrEntity = entity;  return entity; }

注意,由于是反射調用靜態方法,并且調用方法時候并不需要參數,所以Invoke方法的參數為空。
在C++/CLI中,用nullptr表示空引用,跟C#的null作用一樣。

反射調用索引器

SOD實體類可以通過索引器來訪問對象屬性,例如下面的C#代碼:

int id=(int)CurrEntity["ID"];CurrEntity["Name"]="張三";string name=(string)CurrEntity["Name"];//張三

下面,我們研究如何通過索引器來給實體類的屬性賦值:

我們定義一個 EntityHelper的C++/CLI類,在中間添加下面的代碼:

private: Type^ entityBuilderType; MethodInfo^ mset;  Object^ _CurrEntity; //Action<String^, Object^>^ idxAction; void SetPropertyValue(Object^ entity, MethodInfo^ propMethod, String^ propName, Object^ value) {  array<Object^>^ paraArr = gcnew array<Object^>{propName, value};  propMethod->Invoke(entity, paraArr); }public:void set(Object^ value){ this->mset = _CurrEntity->GetType()->GetMethod("set_Item", BindingFlags::Public | BindingFlags::Instance); //this->idxAction= (Action<String^, Object^>^)Delegate::CreateDelegate(Action<String^, Object^>::typeid, _CurrEntity, this->mset);}void SetPropertyValue(String^ propName, Object^ value){ this->SetPropertyValue(this->CurrEntity, this->mset, propName, value); //參數類型為 Object的委托,可能沒有性能優勢,反而更慢。 //this->idxAction(propName, value);}

對索引器的訪問,實際上就是調用類的 set_Item 方法,VS編譯器會給包含索引器的對象生成這個方法,一般來說我們會對要反射調用的方法創建一個委托,但是實驗證明,對索引器使用委托方法調用,反而效率不如直接反射調用,即下面的代碼:

void SetPropertyValue(Object^ entity, MethodInfo^ propMethod, String^ propName, Object^ value) {  array<Object^>^ paraArr = gcnew array<Object^>{propName, value};  propMethod->Invoke(entity, paraArr); }

注:C++/CLI 的數組,也可以通過{ } 進行初始化。

一切準備就緒,下面可以通過以下步驟提交集合數據給.NET方法了:

1,反射.NET方法,獲取參數的泛型形參類型;

2,創建此泛型形參的泛型List對象實例;

3,遍歷C++集合(列表list),將結構數據賦值給動態創建的實體類對象;

4,添加動態實體類到泛型List對象集合內;

5,反射調用.NET方法,提交數據。

//示例1:直接調用.NET強類型的參數方法 //僅僅適用于有一個參數的情況并且要求是泛型類型參數 bool SaveUsers(std::list<CppUserInfo> users) {  MethodInfo^ method = dotnetObject->GetType()->GetMethod("SaveUsers", BindingFlags::Public | BindingFlags::Instance);  array<ParameterInfo^>^ pars = method->GetParameters();  Type^ paraType= pars[0]->ParameterType;  Type^ interfaceType = paraType->GetGenericArguments()[0];  IList^ realList = CreateGenericList(interfaceType);  Object^ userObj = helper->CreateEntityFromInterface(interfaceType);  for each (CppUserInfo user in users)  {  helper->CurrEntity = ((ICloneable^)userObj)->Clone();//使用克隆,避免每次反射  helper->SetPropertyValue("ID", user.ID);  helper->SetPropertyValue("Name", gcnew String(user.Name));  helper->SetPropertyValue("Birthday", Covert2NetDateTime(user.Birthday));  realList->Add(helper->CurrEntity);  }  Object^ result= method->Invoke(dotnetObject, gcnew array<Object^>{ realList});  return (bool)result; }

使用弱類型集合傳輸數據

當委托遇到協變和逆變

看看下面兩個委托方法,哪個可以綁定到本文說的這個.NET方法:

bool SaveUsers(IList<IUserInfo> users){ }Func<List<IUserInfo>,bool> fun;Func<List<Object>,bool> fun2;

很明顯,委托方法 fun2不能綁定,因為參數是 in 的,不是方法out的,所以調用的參數類型不能使用派生程度更小的類型;

再看看下面這種情況:

List<IUserInfo> GetUsers(string likeName){ }Func<string,IEnumerable<IUserInfo>> fun;Func<string,IEnumerable> fun2;

這里,fun,fun2都可以綁定到方法上,因為泛型方法的形參作為返回值,是out的,可以使用派生程度更小的類型。

這是不是很熟悉的泛型類型的 協變和逆變?

我們知道,反射的時候,利用委托綁定要反射的方法,能夠大大提高方法的調用效率,所以對于我們的方法參數,如果調用的時候無法獲知具體的類型,從而無法正確構造合適的委托方法,不如退而求其次,讓被調用的方法參數采用弱類型方式,這樣就可以構造對應的委托方法了。

因此,對我們.NET方法中的 SaveUsers 進行改造:

public bool SaveUsers(IList<IUserInfo> users) {  UserDb.AddRange(users);  return true; } public IUserInfo CreateUserObject() {  return EntityBuilder.CreateEntity<IUserInfo>(); } public bool SaveUsers2(IEnumerable<Object> para) {  var users = from u in para   select u as IUserInfo;  return SaveUsers (users.ToList()); }

這里增加一個方法 SaveUsers2,它采用IEnumerable<Object> ,而不是更為具體的  IList<IUserInfo>,那么采用下面的方式構造方法 SaveUsers2 對應的委托方法就可以了:

MethodInfo^ method = dotnetObject->GetType()->GetMethod("SaveUsers2", BindingFlags::Public | BindingFlags::Instance);Func<System::Collections::Generic::IEnumerable<Object^>^,bool>^ fun2 =   (Func<System::Collections::Generic::IEnumerable<Object^>^, bool>^)Delegate::CreateDelegate(System::Func<Collections::Generic::IEnumerable<Object^>^, bool>::typeid,  this->dotnetObject, method);

這樣要構造一個泛型List就不必像之前的方法那么麻煩了:

System::Collections::Generic::List<Object^>^ list = gcnew System::Collections::Generic::List<Object^>;

反射調用SaveUser2完整的代碼如下:

//示例2:調用.NET弱類型的參數方法,以便通過委托方法調用 //構建委托方法比較容易,適用于參數數量多于1個的情況, bool SaveUsers2(std::list<CppUserInfo> users) {  MethodInfo^ method = dotnetObject->GetType()->GetMethod("SaveUsers2", BindingFlags::Public | BindingFlags::Instance);  Func<System::Collections::Generic::IEnumerable<Object^>^,bool>^ fun2 =   (Func<System::Collections::Generic::IEnumerable<Object^>^, bool>^)Delegate::CreateDelegate(System::Func<Collections::Generic::IEnumerable<Object^>^, bool>::typeid,   this->dotnetObject, method);  Object^ userObj = CreateUserObject();  System::Collections::Generic::List<Object^>^ list = gcnew System::Collections::Generic::List<Object^>;  for each (CppUserInfo user in users)  {  helper->CurrEntity = ((ICloneable^)userObj)->Clone();//使用克隆,避免每次反射  helper->SetPropertyValue("ID", user.ID);  helper->SetPropertyValue("Name", gcnew String(user.Name));  helper->SetPropertyValue("Birthday", Covert2NetDateTime(user.Birthday));  list->Add(helper->CurrEntity);  }  bool result = fun2(list);  return result; }

性能測試

C++/CLI 反射性能測試

為了測試 C++/CLI 反射調用兩種方案(直接反射調用,委托方法調用)的效率,我們循環1000次測試,下面是測試代碼:

NetLibProxy::UserProxy^ proxy = gcnew NetLibProxy::UserProxy("..//NetLib//bin//Debug//NetLib.dll");std::list<CppUserInfo> list = proxy->GetUsers("張"); System::Console::WriteLine("C++ Get List data From .NET function,OK."); System::Diagnostics::Stopwatch^ sw = gcnew System::Diagnostics::Stopwatch; sw->Start(); for (int i = 0; i<1000; i++) proxy->SaveUsers(list); sw->Stop(); System::Console::WriteLine("1,1000 loop,C++ Post List data To .NET function,OK.use time(ms):{0}",sw->ElapsedMilliseconds); sw->Restart(); for(int i=0;i<1000;i++) proxy->SaveUsers2(list); sw->Stop(); System::Console::WriteLine("2,1000 loop,C++ Post List data To .NET function,OK..use time(ms):{0}", sw->ElapsedMilliseconds);

不調試,直接執行:

C++ Get List data From .NET function,OK.1,1000 loop,C++ Post List data To .NET function,OK.use time(ms):652,1000 loop,C++ Post List data To .NET function,OK..use time(ms):48

可見,雖然在.NET程序端,我們使用了弱類型的泛型集合,綜合起來還是反射+委托方法執行,效率要高。

所以如果你能夠適當對要調用的.NET方法進行封裝,那么可采用使用弱類型集合傳輸數據的方案,否則,就在C++/CLI端多寫2行代碼,使用強類型傳輸數據的方案。

與.NET直接調用和反射的性能比較

在本篇的方案中,都是C++反射來調用.NET方法的,如果都是在.NET應用程序中直接調用或者反射.NET方法,性能差距有多少呢?

我們模擬文中 C++/CLI的UserProxy,寫一個.NET中的 UserProxy:

struct UserStruct {  public int ID;  public string Name;  public DateTime Birthday; } class UserProxy {  User user;  public UserProxy()  {   user = new User();  }  public List<UserStruct> GetUsers(string likeName)  {   List<UserStruct> result = new List<NetApp.UserStruct>();   var list = user.GetUsers(likeName);   foreach (var item in list)   {    UserStruct us;    us.ID = item.ID;    us.Name = item.Name;    us.Birthday = item.Birthday;    result.Add(us);   }   return result;  }  public bool SaveUsers(IList<UserStruct> users)  {   List<IUserInfo> list = new List<IUserInfo>();   IUserInfo userObj = user.CreateUserObject();   foreach (var item in users)   {    IUserInfo currUser = (IUserInfo)((ICloneable)userObj).Clone();    currUser.ID = item.ID;    currUser.Name = item.Name;    currUser.Birthday = item.Birthday;    list.Add(currUser);   }   bool result = user.SaveUsers(list);   return result;  }  Object CreateUserObject()  {   MethodInfo method = user.GetType().GetMethod("CreateUserObject", BindingFlags.Public | BindingFlags.Instance);   Func<Object> fun = (Func<Object>)Delegate.CreateDelegate(typeof( Func<Object>), user, method);   return fun();  }  //反射+委托  public bool SaveUsers2(IList<UserStruct> users)  {   MethodInfo method = user.GetType().GetMethod("SaveUsers2", BindingFlags.Public | BindingFlags.Instance);   Func<System.Collections.Generic.IEnumerable<Object>, bool> fun2 = (Func<System.Collections.Generic.IEnumerable<Object>, bool>)Delegate.CreateDelegate(typeof( System.Func<System.Collections.Generic.IEnumerable<Object>, bool>),    user, method);   List<IUserInfo> list = new List<IUserInfo>();   object userObj = CreateUserObject();   foreach (var item in users)   {    IUserInfo currUser = (IUserInfo)((ICloneable)userObj).Clone();    currUser.ID = item.ID;    currUser.Name = item.Name;    currUser.Birthday = item.Birthday;    list.Add(currUser);   }   bool result = fun2(list);   return result;  }}.Net UserProxy

然后同樣循環1000此調用,直接執行,看執行結果:

1,1000 loop,.NET Post List data To .NET function,OK.use time(ms):42,1000 loop,.NET Reflection Post List data To .NET function,OK.use time(ms):14

可見,.NET 平臺內調用,反射+委托的性能是接近于直接方法調用的。
綜合對比,C++/CLI中反射調用.NET,比起在.NET平臺內部反射調用,性能沒有很大的差距,所以C++/CLI中反射調用.NET是一個可行的方案。

總結

C++/CLI是一種很好的混合編寫本機代碼與.NET托管代碼的技術,使用它反射調用.NET方法也是一種可行的方案,結合PDF.NET SOD框架的實體類特征,可以更加方便的簡化C++/CLI反射代碼的編寫并且提高C++代碼與.NET代碼通信的效率。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久高潮国产精品视| 97精品国产97久久久久久免费| 欧洲亚洲在线视频| 欧美日韩性视频在线| 成人激情视频网| 在线视频亚洲欧美| 欧美性猛交xxxx黑人| 久久久久久久999| 国产一区二区三区中文| 美女撒尿一区二区三区| 国产女人精品视频| 日韩精品免费在线观看| 久久欧美在线电影| 海角国产乱辈乱精品视频| 亚洲精品视频在线观看视频| 国产在线观看不卡| 91色精品视频在线| 97色在线播放视频| 国产精品高清免费在线观看| 欧美放荡办公室videos4k| 亚洲第一综合天堂另类专| 国产精品久久久久999| 日韩精品高清视频| 久久免费视频这里只有精品| 欧美激情一区二区三区成人| 日本高清久久天堂| 国产视频精品久久久| 午夜精品久久久久久99热软件| 欧美在线日韩在线| 深夜精品寂寞黄网站在线观看| 高清一区二区三区日本久| 蜜臀久久99精品久久久久久宅男| 亚洲第一页中文字幕| 欧美激情影音先锋| 成人激情视频在线播放| 国产在线精品成人一区二区三区| 日韩av在线播放资源| 亚洲国产成人久久综合一区| 国产亚洲欧洲高清| 国产精品久久二区| 成人中文字幕在线观看| 成人免费视频网址| 伊人久久久久久久久久久| 亚洲的天堂在线中文字幕| 久久久久日韩精品久久久男男| 久久久人成影片一区二区三区观看| 久久久久北条麻妃免费看| 欧美激情一区二区三区成人| 日韩有码在线视频| 国产成人激情视频| 91视频8mav| 精品网站999www| 8050国产精品久久久久久| 亚洲91精品在线| 97国产精品久久| 自拍偷拍亚洲区| 91精品国产色综合久久不卡98口| 午夜精品一区二区三区在线视频| 久久免费精品日本久久中文字幕| 国产97免费视| 亚洲成人国产精品| 久久久久久久影院| 国产精品看片资源| 欧美精品18videos性欧| 中文字幕日韩在线播放| 日韩网站在线观看| 成人av在线亚洲| 日韩中文字幕网站| 久久免费视频在线| 欧美日韩一区二区三区在线免费观看| 91理论片午午论夜理片久久| 亚洲午夜精品久久久久久性色| 亚洲欧美中文日韩在线| 北条麻妃一区二区在线观看| 国产欧美一区二区白浆黑人| 欧美成aaa人片免费看| 亚洲人成毛片在线播放| 国产欧美一区二区白浆黑人| 亚洲已满18点击进入在线看片| 精品国产乱码久久久久久婷婷| yellow中文字幕久久| 欧美大尺度电影在线观看| 国产成人精品午夜| 欧美精品videossex性护士| 亚洲欧洲成视频免费观看| 精品magnet| 欧美色xxxx| 国产成人在线精品| 成人欧美一区二区三区在线| 亚洲xxxx视频| 97久久久久久| 538国产精品一区二区免费视频| 欧美床上激情在线观看| 久久免费视频在线观看| 亚洲免费小视频| 成人444kkkk在线观看| 久久久精品国产一区二区| 欧美激情伊人电影| 欧美自拍大量在线观看| 久久久伊人欧美| 国产精品麻豆va在线播放| 欧美激情亚洲自拍| 社区色欧美激情 | 色狠狠av一区二区三区香蕉蜜桃| 日韩经典中文字幕| 久青草国产97香蕉在线视频| 97视频在线观看视频免费视频| 欧美成人第一页| 久久精品99久久香蕉国产色戒| 欧美日韩电影在线观看| 欧美成人三级视频网站| 亚洲激情在线观看视频免费| 黄色一区二区在线| 久久精彩免费视频| 日韩欧美福利视频| 国产日韩欧美在线视频观看| 国产精品视频免费在线| 91精品国产自产在线| 国产亚洲日本欧美韩国| 亚洲国产精品成人精品| 日韩av影片在线观看| 亚洲аv电影天堂网| 久久久av一区| 国产精品丝袜白浆摸在线| 国产成人在线一区二区| 久久精品国产亚洲精品2020| 亚洲国产精品久久久久久| 亚洲国产精品美女| 91sao在线观看国产| 午夜精品久久久久久久男人的天堂| 国产精品黄色影片导航在线观看| 亚洲a中文字幕| 欧美日韩国产一中文字不卡| 成人黄色免费在线观看| 日av在线播放中文不卡| 久久激情视频久久| 日韩精品在线影院| 成人综合网网址| 精品magnet| 日本一欧美一欧美一亚洲视频| 欧美视频专区一二在线观看| 国产精品一区二区三区在线播放| 亚洲精品国产欧美| 色妞一区二区三区| 久久成人这里只有精品| 午夜精品久久久久久99热软件| 亚洲欧美制服中文字幕| 国产精品视频999| 国产亚洲精品综合一区91| 国产91在线播放九色快色| 国产精品jizz在线观看麻豆| 日本成熟性欧美| 亚洲欧美国产一本综合首页| 国产69精品久久久久99| 亚洲精品视频在线观看视频| 欧美性猛交xxxx黑人猛交| 国产精品一区二区三区久久| 亚洲丁香久久久| 国产精品旅馆在线| 欧美裸体视频网站| 久久久久久久国产精品| 亚洲欧美日韩成人| 亚洲综合自拍一区| 久久激情视频久久|