在C++中反射调用.NET的方法(二)

2020-01-06 16:55:36王旭

在上面的代码中,通过委托方法调用:


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