程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 在C++中反射調用.NET的辦法(二)

在C++中反射調用.NET的辦法(二)

編輯:關於C++

在C++中反射調用.NET的辦法(二)。本站提示廣大學習愛好者:(在C++中反射調用.NET的辦法(二))文章只能為提供參考,不一定能成為您想要的結果。以下是在C++中反射調用.NET的辦法(二)正文


反射調用前往復雜對象的.NET辦法

定義數據接口

上一篇在C++中反射調用.NET(一)中,我們復雜的引見了如何運用C++/CLI並且初步運用了反射調用.NET順序集的復雜辦法,明天我們看看如何在C++與.NET順序集之間傳遞復雜對象。

先看看.NET順序集的一個前往對象的辦法:

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

其中 IUserInfo是一個用戶信息接口:

using System;
namespace NetLib
{
 public interface IUserInfo
 {
 DateTime Birthday { get; set; }
 int ID { get; set; }
 string Name { get; set; }
 }
}

接口內容很復雜,有int,string,DateTime三品種型的屬性,所以可以把它當做.NET與C++傳遞數據的DTO對象接口。

在辦法 GetUserByID 中,有一行代碼:

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

EntityBuilder對象是PDF.NET SOD框架中的一個實體結構器,調用CreateEntity辦法可以依據一個接口創立一個靜態實體類對象,經過這種方式,我們可以不必去關懷實體類的結構細節,僅僅關懷辦法調用的數據接口。在前面的示例中,我們都會經過這種接口對象的方式來傳遞數據。

綁定委托辦法

上面我們來看看如何在C++/CLI中反射調用GetUserByID 這個辦法。

雖然辦法前往的是IUserInfo,但是關於我們的C++順序端來說,它並不知道IUserInfo這個接口對象,由於此接口沒有在C++順序端定義,C++順序也沒用援用它所在的.NET順序集,所以我們在反射調用GetUserByID 辦法的時分,只能運用“弱類型”的Object,僥幸的是我們調用的是前往值,而不是參數(反過去就不行,前面會有引見),創立上面的委托對象是合法的:

Func<int, Object> fun;

詳細的C++/CLI反射代碼如下:

CppUserInfo GetUserByID(int userId)
 {
  //調用.NET辦法,失掉後果
  MethodInfo^ method = dotnetObject->GetType()->GetMethod("GetUserByID", BindingFlags::Public | BindingFlags::Instance);
  Func<int, Object^>^ fun = (Func<int, Object^>^)Delegate::CreateDelegate(Func<int, Object^>::typeid, this->dotnetObject, method);
  Object^ result = fun(userId);
  //轉換托管類型數據到本機構造體
  Func<String^, Object^>^ entityProp =EntityHelper::EntityCallDelegate(result);
  CppUserInfo user;
  user.ID = (int)entityProp("ID");
  user.Name = (String^)entityProp("Name");// MarshalString((String^)entityProp("Name"));
  user.Birthday = Convert2CppDateTime((DateTime^)entityProp("Birthday"));
  return user;
 }

在下面的代碼中,經過委托辦法調用:

Object^ result = fun(userId); 

運用SOD DTO 對象

我們失掉了.NET順序集的辦法前往的DTO對象,但是如何取出它的數據賦值給我們的C++本機代碼呢?

所以這裡觸及到2個問題:

1,從Object對象取出數據;

2,將數據轉換並且賦值給C++本地數據構造

關於第一個問題,我們可以反射DTO對象的屬性,然後跟本地數據接口逐個對應,但是,原本我們曾經在反射調用辦法了,再來一次反射事情就復雜了。

幸虧,我們的DTO接口對象它是一個靜態創立的SOD實體類對象,由於SOD實體類有相似“字典”的功用,可以經過相關辦法停止訪問。

實體類基類的一個辦法定義:

public object PropertyList(string propertyFieldName)

我們反射此辦法並且綁定一個委托對象來調用它:

 static Func<String^, Object^>^ EntityCallDelegate(Object^ entity)
 {
  //實體類基類的一個辦法定義:
  //public object PropertyList(string propertyFieldName)
  Type^ base = entity->GetType()->BaseType;
  MethodInfo^ methodEntity = base->GetMethod("PropertyList", BindingFlags::Public | BindingFlags::Instance);
  Func<String^, Object^>^ funEntity = (Func<String^, Object^>^)Delegate::CreateDelegate(Func<String^, Object^>::typeid, 
      entity, methodEntity);
  //示例 String^ result = (String^)funEntity("Name");
  return funEntity;
 }

然後,就能像上面這樣運用了:

Func<String^, Object^>^ entityProp =EntityHelper::EntityCallDelegate(result);
int id = (int)entityProp("ID");

將.NET對象轉換到C++構造體

在示例中,我們定義了一個CppUserInfo構造體:

struct CppUserInfo
{
 int ID;
 //wstring Name;
 CString Name;
 tm Birthday;
};

托管字符串與本機字符串

這個構造體跟C#版本的接口 IUserInfo對應,但是構造體成員有幾個需求留意的中央:

CString Name;

字符串類型的“名字”成員,要在C++中運用字符串類型,必需在C++文件中包括上面的頭文件:
假如不是 MFC使用順序,包括上面這個:

#include <atlstr.h>

否則,需求包括這個頭文件:

#include <cstringt.h>  

假如不是運用CString,而是 wstring,那麼需求定義一個辦法來完成托管字符串到本機字符串的轉換: 

// 
 //要運用上面的辦法,請先 #include <string> 
 //
 static wstring MarshalString(String ^ s) {
  wstring os;
  const wchar_t* chars =
   (const wchar_t*)(Marshal::StringToHGlobalUni(s)).ToPointer();
  os = chars;
  Marshal::FreeHGlobal(IntPtr((void*)chars));
  return os;
 }

下面的辦法聲明了一個 wchar_t* 類型的指針,在辦法開頭必需釋放此指針占用的內存,所以這種方式的轉換還是比擬費事。
有關托管字符串跟C++本機字符串的轉換。

托管日期與本機日期數據

在C++中表示日期的構造體是 tm,但是需求留意的是 tm的year局部僅可以表示與1900的差值,所以我們可以寫上面2個辦法來復雜的轉換:

 static tm Convert2CppDateTime(DateTime^ dt)
 {
  tm result;
  result.tm_year = dt->Year - 1900;
  result.tm_mon = dt->Month;
  result.tm_wday = dt->Day;
  return result;
 }
 static DateTime^ Covert2NetDateTime(tm cppDate)
 {
  return gcnew DateTime(
   cppDate.tm_year + 1900, 
   cppDate.tm_mon, 
   cppDate.tm_wday
  );
 }

有了字符串跟日期類型的.NET與C++的互相轉換,根本上就可以運用.NET的DTO對象了,由於其它數字類型只需類型兼容,是可以直接運用的,比方int類型。

轉換到本機構造體

上面再回來看看 GetUserByID 辦法內的對象數據轉換局部:

//轉換托管類型數據到本機構造體
   Func<String^, Object^>^ entityProp =EntityHelper::EntityCallDelegate(result);
   CppUserInfo user;
   user.ID = (int)entityProp("ID");
   user.Name = (String^)entityProp("Name");// MarshalString((String^)entityProp("Name"));
   user.Birthday = Convert2CppDateTime((DateTime^)entityProp("Birthday"));

如今再看看,采用相似“字典”訪問方式的SOD DTO對象,給C++本地構造體轉換賦值數據,就很方便了,這也是本篇選擇SOD框架作為C++與.NET通訊的緣由了。

為何不運用序列化的問題

在停止散布式跨平台調用的時分,序列化經常作為一個無效手腕被少量運用,但是我們的使用有幾個特點:

1,沒有散布式,在進程內停止不同言語平台調用;

2,不知道反序列化的類型,由於C++沒有直接援用任何.NET框架本身之外的.NET順序集;

3,序列化需求運用反射,而我們原本曾經在反射了,會減輕擔負;

除此之外,運用序列化還會有額定的任務:

4,運用序列化會要求被調用端停止額定的封裝;

5,單方需求制定通用的通訊協議,並且定制序列化進程,比方罕見RPC框架商定的序列化協議

所以,經過細心思索後,保持了運用序列化方式來停止C++與.NET停止進程內通訊的想法。

以上所述是給大家引見的在C++中反射調用.NET的辦法(二),希望對大家有所協助,假如大家有任何疑問歡送給我留言,會及時回復大家的!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved