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

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

編輯:關於C++

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


為什麼要在C++中調用.NET

普通狀況下,我們經常會在.NET順序中調用C/C++的順序,運用P/Invoke方式停止調用,在編寫代碼代碼的時分,首先要導入DLL文件,然後在依據C/C++的頭文件編寫特殊的C#平台調用代碼,例如像上面這個樣子:

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

詳細的進程,可以參考之前我這篇文章:《C#調用C和C++函數的一點區別》

有時分,我們也會有在C++中調用.NET的需求,比方我們在維護一個大型的C++使用順序,它年代長遠,如今需求添加一些新功用,而這些功用在.NET中曾經有了,只需求調用它即可,假如為了方便想要用.NET重寫這個C++使用順序是不太理想的,幸虧,C++/CLI提供了一個簡便的方案使得可以在C++中直接編寫.NET順序,所以C++/CLI代表托管和本地編程的結合,可以在托管代碼中直接運用本地代碼,也可以反過去,這樣結合了C++本地代碼的高效性和.NET代碼的弱小性,看起來是十分有潛力的。

運用C++/CLI停止.NET編程

要停止C++/CLI編程,只需求停止上面的步驟:

1,添加.NET順序集的使用;

2,修正C++項目屬性,配置屬性->公共言語運轉時支持-公共言語運轉時支持(/clr)

但是,為了堅持C++與.NET使用順序的獨立性,要求不能將.NET的DLL文件放到C++的使用順序目錄下,因而上述步驟1不可行,需求在C++代碼中運用反射來調用.NET。

留意,本文說的C++反射調用,不是對C++本身停止封裝的反射功用,而是在C++/CLI代碼中反射調用.NET代碼,原理上跟你在.NET使用中反射調用另外一個.NET的順序集一個道理。

首先,我們樹立一個名字叫CppNetTest的處理方案,添加3個項目:

1,CppConsoleTest---一個C++控制台項目,在項目中更改屬性支持CLR;

2,NetApp--一個.NET控制台使用順序,作為比照示例代碼,方便編寫C++/CLI代碼參考;

3,NetLib--一個.NET類庫順序集,它將被1和2項目停止反射調用。

我們先在NetLib項目寫一個復雜的.NET 類,這個類的辦法外部沒有復雜的業務邏輯代碼,僅僅用來供反射調用測試:

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或許數組,不影響 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 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項目的頭文件中,添加一個 UserProxy.h 的C++頭文件,在文件中添加上面的命名空間:

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

這樣我們就可以運用反射相關的類型了。

在UserProxy類中,先編寫我們需求的結構函數:

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的類必需是“援用”類型,所以需求加關鍵字 ref,即:

public ref class UserProxy{}

一切的.NET援用類型,在運用的時分,都必需在類型名字後加 ^ 符號,例如上面定一個.NET字符串類型變量:

String^ assemblyFile; 

帶^符號的變量,在C++/CLI中稱為 “句柄”對象,用來跟C++本地代碼的“指針”相區別。

在C++中,類的成員用 -> 符號調用,命名空間或許類的靜態成員,用::調用,例如下面的結構函數中的代碼:

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

 留意:在本例中需求.NET類庫項目援用 PDF.NET SOD框架,在項目的“管理Nuget順序包”外面搜索 PDF.NET.SOD.Core 添加此援用即可。
學會了這些C++的根底語法,那麼編寫C++/CLI代碼就沒有次要的妨礙了。

在C++/CLI中運用反射

反射調用第一個.NET類的辦法

上面的辦法,將會反射調用 User類的一個最復雜的辦法 :

public int GetUserID(string IdString){}

該辦法只要一個一個參數和一個復雜的前往值,上面是C++/CLI的反射調用代碼:

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

留意這裡創立了一個 Func<String,int>的委托辦法,運用委托可以簡化我們的反射調用並且有時分還可以進步效率,在這段代碼中,有1個要留意的中央:

Func<String^, int>::typeid

這是C++/CLI特殊的語法,表示獲取“句柄”類型的類型ID,實踐上它的後果就Type對象,同等於C#的
typeof(Func<string,int>)

PS:十分遺憾的是,typeid方式,沒法失掉上面類型的類型值:
typeof(Func<,>),這給我們在靜態結構泛型對象的時分形成了很大的困惑。

再看一個復雜辦法的反射:

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是值類型,因而在停止類型聲明的時分,不需求加^符號,僅需求對Func委托加上^句柄標志。

有了這2個復雜的辦法,我們來看看如何調用這個.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,第一個C++/CLI代碼調用成功,而且還是反射調用的,心境小沖動一下。

有關C++/CLI的反射,委托的詳細材料,可以參考MSDN的引見:

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

在下一篇,我們將持續探求C++/CLI 反射調用.NET中能夠遇到"深坑",因而僅計劃吧本篇文章作為一個“入門”,以免大家心生恐懼,錯過了應戰艱險的時機。

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

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