在C++中反射調(diào)用.NET的方法(二)
反射調(diào)用返回復(fù)雜對象的.NET方法
定義數(shù)據(jù)接口
上一篇在C++中反射調(diào)用.NET(一)中,我們簡單的介紹了如何使用C++/CLI并且初步使用了反射調(diào)用.NET程序集的簡單方法,今天我們看看如何在C++與.NET程序集之間傳遞復(fù)雜對象。
先看看.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; }
}
}
接口內(nèi)容很簡單,有int,string,DateTime三種類型的屬性,所以可以把它當做.NET與C++傳遞數(shù)據(jù)的DTO對象接口。
在方法 GetUserByID 中,有一行代碼:
IUserInfo userinfo= EntityBuilder.CreateEntity<IUserInfo>();
EntityBuilder對象是PDF.NET SOD框架中的一個實體構(gòu)造器,調(diào)用CreateEntity方法可以根據(jù)一個接口創(chuàng)建一個動態(tài)實體類對象,通過這種方式,我們可以不用去關(guān)心實體類的構(gòu)造細節(jié),僅僅關(guān)心方法調(diào)用的數(shù)據(jù)接口。在后面的示例中,我們都會通過這種接口對象的方式來傳遞數(shù)據(jù)。
綁定委托方法
下面我們來看看如何在C++/CLI中反射調(diào)用GetUserByID 這個方法。
雖然方法返回的是IUserInfo,但是對于我們的C++程序端來說,它并不知道IUserInfo這個接口對象,因為此接口沒有在C++程序端定義,C++程序也沒用引用它所在的.NET程序集,所以我們在反射調(diào)用GetUserByID 方法的時候,只能使用“弱類型”的Object,幸運的是我們調(diào)用的是返回值,而不是參數(shù)(反過來就不行,后面會有介紹),創(chuàng)建下面的委托對象是合法的:
Func<int, Object> fun;
詳細的C++/CLI反射代碼如下:
CppUserInfo GetUserByID(int userId)
{
//調(diào)用.NET方法,得到結(jié)果
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);
//轉(zhuǎn)換托管類型數(shù)據(jù)到本機結(jié)構(gòu)體
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;
}
在上面的代碼中,通過委托方法調(diào)用:
Object^ result = fun(userId);
使用SOD DTO 對象
我們得到了.NET程序集的方法返回的DTO對象,但是如何取出它的數(shù)據(jù)賦值給我們的C++本機代碼呢?
所以這里涉及到2個問題:
1,從Object對象取出數(shù)據(jù);
2,將數(shù)據(jù)轉(zhuǎn)換并且賦值給C++本地數(shù)據(jù)結(jié)構(gòu)
對于第一個問題,我們可以反射DTO對象的屬性,然后跟本地數(shù)據(jù)接口一一對應(yīng),但是,本來我們已經(jīng)在反射調(diào)用方法了,再來一次反射事情就復(fù)雜了。
幸好,我們的DTO接口對象它是一個動態(tài)創(chuàng)建的SOD實體類對象,由于SOD實體類有類似“字典”的功能,可以通過相關(guān)方法進行訪問。
實體類基類的一個方法定義:
public object PropertyList(string propertyFieldName)
我們反射此方法并且綁定一個委托對象來調(diào)用它:
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對象轉(zhuǎn)換到C++結(jié)構(gòu)體
在示例中,我們定義了一個CppUserInfo結(jié)構(gòu)體:
struct CppUserInfo
{
int ID;
//wstring Name;
CString Name;
tm Birthday;
};
托管字符串與本機字符串
這個結(jié)構(gòu)體跟C#版本的接口 IUserInfo對應(yīng),但是結(jié)構(gòu)體成員有幾個需要注意的地方:
CString Name;
字符串類型的“名字”成員,要在C++中使用字符串類型,必須在C++文件中包含下面的頭文件:
如果不是 MFC應(yīng)用程序,包含下面這個:
#include <atlstr.h>
否則,需要包含這個頭文件:
#include <cstringt.h>
如果不是使用CString,而是 wstring,那么需要定義一個方法來實現(xiàn)托管字符串到本機字符串的轉(zhuǎn)換:
//
//要使用下面的方法,請先 #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* 類型的指針,在方法結(jié)尾必須釋放此指針占用的內(nèi)存,所以這種形式的轉(zhuǎn)換還是比較麻煩。
有關(guān)托管字符串跟C++本機字符串的轉(zhuǎn)換。
托管日期與本機日期數(shù)據(jù)
在C++中表示日期的結(jié)構(gòu)體是 tm,但是需要注意的是 tm的year部分僅能夠表示與1900的差值,所以我們可以寫下面2個方法來簡單的轉(zhuǎn)換:
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++的相互轉(zhuǎn)換,基本上就能夠使用.NET的DTO對象了,因為其它數(shù)字類型只要類型兼容,是可以直接使用的,比如int類型。
轉(zhuǎn)換到本機結(jié)構(gòu)體
下面再回來看看 GetUserByID 方法內(nèi)的對象數(shù)據(jù)轉(zhuǎn)換部分:
//轉(zhuǎn)換托管類型數(shù)據(jù)到本機結(jié)構(gòu)體
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"));
現(xiàn)在再看看,采用類似“字典”訪問方式的SOD DTO對象,給C++本地結(jié)構(gòu)體轉(zhuǎn)換賦值數(shù)據(jù),就很方便了,這也是本篇選擇SOD框架作為C++與.NET通信的原因了。
為何不使用序列化的問題
在進行分布式跨平臺調(diào)用的時候,序列化常常作為一個有效手段被大量使用,但是我們的應(yīng)用有幾個特點:
1,沒有分布式,在進程內(nèi)進行不同語言平臺調(diào)用;
2,不知道反序列化的類型,因為C++沒有直接引用任何.NET框架自身之外的.NET程序集;
3,序列化需要使用反射,而我們本來已經(jīng)在反射了,會加重負擔;
除此之外,使用序列化還會有額外的工作:
4,使用序列化會要求被調(diào)用端進行額外的封裝;
5,雙方需要制定通用的通信協(xié)議,并且定制序列化過程,比如常見RPC框架約定的序列化協(xié)議
所以,經(jīng)過仔細考慮后,放棄了使用序列化方式來進行C++與.NET進行進程內(nèi)通信的想法。
以上所述是小編給大家介紹的在C++中反射調(diào)用.NET的方法(二),希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復(fù)大家的!
欄 目:C語言
下一篇:C語言中函數(shù)參數(shù)的入棧順序詳解及實例
本文標題:在C++中反射調(diào)用.NET的方法(二)
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/1761.html
您可能感興趣的文章
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對數(shù)怎么表達
- 04-02c語言沒有round函數(shù) round c語言
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10使用C++實現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10APUE筆記之:進程環(huán)境詳解
- 01-10c++中inline的用法分析
- 01-10如何尋找數(shù)組中的第二大數(shù)


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10C#中split用法實例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 04-02jquery與jsp,用jquery


