欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在C++中反射調(diào)用.NET的方法(一)

 更新時(shí)間:2017年02月05日 10:14:32   投稿:mrr  
為什么要在C++中調(diào)用.NET呢?接下來(lái)通過(guò)本文給大家介紹在C++中反射調(diào)用.NET的方法(一),需要的朋友參考下吧

為什么要在C++中調(diào)用.NET

一般情況下,我們常常會(huì)在.NET程序中調(diào)用C/C++的程序,使用P/Invoke方式進(jìn)行調(diào)用,在編寫代碼代碼的時(shí)候,首先要導(dǎo)入DLL文件,然后在根據(jù)C/C++的頭文件編寫特殊的C#平臺(tái)調(diào)用代碼,例如像下面這個(gè)樣子:

 [DllImport("Interop.dll",EntryPoint = "Multiply",CharSet = CharSet.Ansi)]
 static extern int Multiply(int factorA, int factorB);

詳細(xì)的過(guò)程,可以參考之前我這篇文章:《C#調(diào)用C和C++函數(shù)的一點(diǎn)區(qū)別》

有時(shí)候,我們也會(huì)有在C++中調(diào)用.NET的需求,比如我們?cè)诰S護(hù)一個(gè)大型的C++應(yīng)用程序,它年代久遠(yuǎn),現(xiàn)在需要增加一些新功能,而這些功能在.NET中已經(jīng)有了,只需要調(diào)用它即可,如果為了方便想要用.NET重寫這個(gè)C++應(yīng)用程序是不太現(xiàn)實(shí)的,幸好,C++/CLI提供了一個(gè)簡(jiǎn)便的方案使得可以在C++中直接編寫.NET程序,所以C++/CLI代表托管和本地編程的結(jié)合,可以在托管代碼中直接使用本地代碼,也可以反過(guò)來(lái),這樣結(jié)合了C++本地代碼的高效性和.NET代碼的強(qiáng)大性,看起來(lái)是非常有潛力的。

使用C++/CLI進(jìn)行.NET編程

要進(jìn)行C++/CLI編程,只需要進(jìn)行下面的步驟:

1,添加.NET程序集的應(yīng)用;

2,修改C++項(xiàng)目屬性,配置屬性->公共語(yǔ)言運(yùn)行時(shí)支持-公共語(yǔ)言運(yùn)行時(shí)支持(/clr)

然而,為了保持C++與.NET應(yīng)用程序的獨(dú)立性,要求不能將.NET的DLL文件放到C++的應(yīng)用程序目錄下,因此上述步驟1不可行,需要在C++代碼中使用反射來(lái)調(diào)用.NET。

注意,本文說(shuō)的C++反射調(diào)用,不是對(duì)C++自身進(jìn)行封裝的反射功能,而是在C++/CLI代碼中反射調(diào)用.NET代碼,原理上跟你在.NET應(yīng)用中反射調(diào)用另外一個(gè).NET的程序集一個(gè)道理。

首先,我們建立一個(gè)名字叫CppNetTest的解決方案,添加3個(gè)項(xiàng)目:

1,CppConsoleTest---一個(gè)C++控制臺(tái)項(xiàng)目,在項(xiàng)目中更改屬性支持CLR;

2,NetApp--一個(gè).NET控制臺(tái)應(yīng)用程序,作為對(duì)比示例代碼,方便編寫C++/CLI代碼參考;

3,NetLib--一個(gè).NET類庫(kù)程序集,它將被1和2項(xiàng)目進(jìn)行反射調(diào)用。

我們先在NetLib項(xiàng)目寫一個(gè)簡(jiǎn)單的.NET 類,這個(gè)類的方法內(nèi)部沒(méi)有復(fù)雜的業(yè)務(wù)邏輯代碼,僅僅用來(lái)供反射調(diào)用測(cè)試:

namespace NetLib
{
  public class User
  {
    static List<IUserInfo> UserDb = new List<IUserInfo>();
    public int GetUserID(string IdString)
    {
      int result = 0;
      int.TryParse(IdString, out result);
      return result;
    }
    public DateTime GetUserBirthday(int userId)
    {
      return new DateTime(1980, 1, 1);
    }
    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;
    }
    //返回List或者數(shù)組,不影響 C++調(diào)用
    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 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());
    }
  }
}

在CppConsoleTest項(xiàng)目的頭文件中,添加一個(gè) UserProxy.h 的C++頭文件,在文件中添加下面的命名空間:

using namespace System;
using namespace System::Reflection;
using namespace Runtime::InteropServices;
using namespace System::Collections;

這樣我們就可以使用反射相關(guān)的類型了。

在UserProxy類中,先編寫我們需要的構(gòu)造函數(shù):

public ref class UserProxy
  {
  private:
    String^ assemblyFile; //"..\\NetLib\\bin\\Debug\\NetLib.dll"
    Object^ dotnetObject;
    Type^ entityBuilderType;
    String^ className = "NetLib.User";
    EntityHelper^ helper;
    
  public:
    UserProxy(String^ assemblyFile)
    {
      this->assemblyFile = assemblyFile;
      Assembly^ ass = Assembly::LoadFrom(this->assemblyFile);
      this->dotnetObject = ass->CreateInstance(className);
      String^ sodPath = System::IO::Path::Combine(System::IO::Path::GetDirectoryName(this->assemblyFile), "PWMIS.Core.dll");
      /*Assembly^ ass_sod = Assembly::LoadFrom(sodPath);
      this->entityBuilderType = ass_sod->GetType("PWMIS.DataMap.Entity.EntityBuilder");*/
      helper = gcnew EntityHelper(sodPath);
    }
}

注意我們的 C++/CLI的類必須是“引用”類型,所以需要加關(guān)鍵字 ref,即:

public ref class UserProxy{}

所有的.NET引用類型,在使用的時(shí)候,都必須在類型名字后加 ^ 符號(hào),例如下面定一個(gè).NET字符串類型變量:

String^ assemblyFile; 

帶^符號(hào)的變量,在C++/CLI中稱為 “句柄”對(duì)象,用來(lái)跟C++本地代碼的“指針”相區(qū)別。

在C++中,類的成員用 -> 符號(hào)調(diào)用,命名空間或者類的靜態(tài)成員,用::調(diào)用,例如上面的構(gòu)造函數(shù)中的代碼:

Assembly^ ass = Assembly::LoadFrom(this->assemblyFile);

 注意:在本例中需要.NET類庫(kù)項(xiàng)目引用 PDF.NET SOD框架,在項(xiàng)目的“管理Nuget程序包”里面搜索 PDF.NET.SOD.Core 添加此引用即可。
學(xué)會(huì)了這些C++的基礎(chǔ)語(yǔ)法,那么編寫C++/CLI代碼就沒(méi)有主要的障礙了。

在C++/CLI中使用反射

反射調(diào)用第一個(gè).NET類的方法

下面的方法,將會(huì)反射調(diào)用 User類的一個(gè)最簡(jiǎn)單的方法 :

public int GetUserID(string IdString){}

該方法只有一個(gè)一個(gè)參數(shù)和一個(gè)簡(jiǎn)單的返回值,下面是C++/CLI的反射調(diào)用代碼:

int GetUserID(String^ iDstring)
{
  MethodInfo^ method = this->dotnetObject->GetType()->GetMethod("GetUserID", BindingFlags::Public | BindingFlags::Instance);
  Func<String^, int>^ fun = (Func<String^, int>^)Delegate::CreateDelegate(Func<String^, int>::typeid, this->dotnetObject, method);
  int result = fun(iDstring);
  
  return result;
}

注意這里創(chuàng)建了一個(gè) Func<String,int>的委托方法,使用委托能夠簡(jiǎn)化我們的反射調(diào)用并且有時(shí)候還能夠提高效率,在這段代碼中,有1個(gè)要注意的地方:

Func<String^, int>::typeid

這是C++/CLI特殊的語(yǔ)法,表示獲取“句柄”類型的類型ID,實(shí)際上它的結(jié)果就Type對(duì)象,等同于C#的
typeof(Func<string,int>)

PS:非常遺憾的是,typeid方式,沒(méi)法得到下面類型的類型值:
typeof(Func<,>),這給我們?cè)趧?dòng)態(tài)構(gòu)造泛型對(duì)象的時(shí)候造成了很大的困惑。

再看一個(gè)簡(jiǎn)單方法的反射:

DateTime GetUserBirthday(int userId)
    {
      MethodInfo^ method = dotnetObject->GetType()->GetMethod("GetUserBirthday", BindingFlags::Public | BindingFlags::Instance);
      Func<int, DateTime>^ fun = (Func<int, DateTime>^)Delegate::CreateDelegate(Func<int, DateTime>::typeid, this->dotnetObject, method);
      DateTime result = fun(userId);
      return result;
    }

注意:由于DateTime是值類型,因此在進(jìn)行類型申明的時(shí)候,不需要加^符號(hào),僅需要對(duì)Func委托加上^句柄標(biāo)記。

有了這2個(gè)簡(jiǎn)單的方法,我們來(lái)看看如何調(diào)用這個(gè).NET方法“代理類”: 

 NetLibProxy::UserProxy^ proxy = gcnew NetLibProxy::UserProxy("..\\NetLib\\bin\\Debug\\NetLib.dll");
  int result= proxy->GetUserID("123456");
  DateTime date = proxy->GetUserBirthday(result);
  System::Console::WriteLine("C++/CLI .Net Proxy Class Call Test Result:\r\n UserID={0},\r\n Birthday={1}", 
    result,date.ToShortDateString());

OK,第一個(gè)C++/CLI代碼調(diào)用成功,而且還是反射調(diào)用的,心情小激動(dòng)一下。

有關(guān)C++/CLI的反射,委托的詳細(xì)資料,可以參考MSDN的介紹:

https://msdn.microsoft.com/zh-cn/library/2x8kf7zx.aspx 使用 C++ 互操作(隱式 PInvoke)
https://msdn.microsoft.com/zh-CN/library/213x8e7w.aspx 泛型委托

在下一篇,我們將繼續(xù)探究C++/CLI 反射調(diào)用.NET中可能遇到"深坑",因此僅打算吧本篇文章作為一個(gè)“入門”,免得大家心生恐懼,錯(cuò)過(guò)了挑戰(zhàn)艱險(xiǎn)的機(jī)會(huì)。

以上所述是小編給大家介紹的在C++中反射調(diào)用.NET的方法(一),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

相關(guān)文章

  • C語(yǔ)言實(shí)現(xiàn)一個(gè)多線程委托模型的示例詳解

    C語(yǔ)言實(shí)現(xiàn)一個(gè)多線程委托模型的示例詳解

    這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)一個(gè)多線程委托模型,這就是一個(gè)使用C語(yǔ)言實(shí)現(xiàn)多線程委托模型的例子,其中包含boss線程和worker線程,可以處理工作線程的異常情況,需要的朋友可以參考下
    2023-06-06
  • EasyC++模板重載

    EasyC++模板重載

    這篇文章主要介紹了C++模板重載,重載的模板的函數(shù)特征,也就是入?yún)⒌臄?shù)量和類型必須有所不同,下面我們講舉例說(shuō)明此內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2021-12-12
  • C++實(shí)現(xiàn)商品管理程序

    C++實(shí)現(xiàn)商品管理程序

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)商品管理程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • C語(yǔ)言中static與extern關(guān)鍵字的深入解析

    C語(yǔ)言中static與extern關(guān)鍵字的深入解析

    在C語(yǔ)言編程中,static和extern是兩個(gè)非常重要的關(guān)鍵字,它們各自有著獨(dú)特的用途,本文將深入探討這兩個(gè)關(guān)鍵字的工作原理、底層實(shí)現(xiàn)機(jī)制以及在實(shí)際開發(fā)中的應(yīng)用,感興趣的小伙伴跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧
    2024-09-09
  • C++中sprintf使用的方法與printf的區(qū)別分析

    C++中sprintf使用的方法與printf的區(qū)別分析

    這篇文章主要介紹了C++中sprintf使用的方法與printf的區(qū)別,實(shí)例分析了sprintf與printf的具體用法及相關(guān)注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-01-01
  • Qt使用QJson模塊實(shí)現(xiàn)解析Json文件

    Qt使用QJson模塊實(shí)現(xiàn)解析Json文件

    在項(xiàng)目開發(fā)過(guò)程中,經(jīng)常會(huì)遇到讀寫Json文件的需求,掌握J(rèn)son文件的操作是基礎(chǔ)中的基礎(chǔ),下面我們就來(lái)看看如何使用QT內(nèi)置的QJson模塊解析Json文件吧
    2023-10-10
  • C++調(diào)用EasyX庫(kù)實(shí)現(xiàn)嫦娥奔月小游戲

    C++調(diào)用EasyX庫(kù)實(shí)現(xiàn)嫦娥奔月小游戲

    這篇文章主要為大家詳細(xì)介紹了C++如何調(diào)用EasyX庫(kù)編寫一個(gè)簡(jiǎn)單的嫦娥奔月小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下
    2023-09-09
  • c語(yǔ)言中assert斷言用法實(shí)例詳解

    c語(yǔ)言中assert斷言用法實(shí)例詳解

    斷言是C語(yǔ)言中一種用于檢查程序中假設(shè)語(yǔ)句正確性的方法,通過(guò)使用斷言,開發(fā)人員可以在程序中插入一些條件,以確保程序的執(zhí)行滿足特定的預(yù)期,這篇文章主要給大家介紹了關(guān)于c語(yǔ)言中assert斷言用法的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • C++實(shí)現(xiàn)堆排序示例

    C++實(shí)現(xiàn)堆排序示例

    這篇文章主要介紹了C++實(shí)現(xiàn)堆排序示例,全文運(yùn)用大量代碼完成堆排序,需要了解的朋友可以參考一下這篇文章
    2021-08-08
  • Qt6子窗口全屏顯示的實(shí)現(xiàn)示例

    Qt6子窗口全屏顯示的實(shí)現(xiàn)示例

    在Qt開發(fā)中,有時(shí)候需要讓程序窗口全屏顯示,本文主要介紹了Qt6子窗口全屏顯示的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04

最新評(píng)論