The reflection call returns a complex object. Net method defines the data interface
The previous article reflects the call in C + +. NET (i), we briefly describe how to use C + +/CLI and initially use a simple method of reflection calling. NET assemblies, today we look at how to pass complex objects between C + + and. NET assemblies.
Look first. NET assembly is a way to return an object:
Public Iuserinfo Getuserbyid (int userId) { iuserinfo userinfo= entitybuilder.createentity< Iuserinfo>(); = userId; " Name _ " + userId; New DateTime (198011); return userinfo; }
Where Iuserinfo is a user information interface:
using System; namespace netlib{ publicinterface iuserinfo { getSet ; } int Get Set ; } string Get Set ; } }}
The interface content is simple, there are int,string,datetime three types of attributes, so it can be considered as. NET and C + + to pass data to the Dto object interface.
In method Getuserbyid, there is a line of code:
Iuserinfo userinfo= entitybuilder.createentity<iuserinfo> ();
The Entitybuilder object is an entity constructor in the pdf.net sod frame, which calls the Createentity method to create a dynamic entity class object based on an interface, so that we can not care about the construction details of the entity class. Just care about the data interface of the method invocation. In the following example, we will pass the data through this interface object.
Binding Delegate Method
Let's take a look at how to reflect the call Getuserbyid in C + +/CLI.
Although the method returns Iuserinfo, for our C + + terminal, it does not know iuserinfo this interface object, because this interface is not defined in the C + + terminal, C + + programs do not reference it. NET assembly, so we can only use "weakly typed" object when reflection calls the Getuserbyid method, fortunately we call the return value instead of the parameter (which, in turn, is not possible, as described later), and it is legal to create the following delegate object:
func<int, object> fun;
Detailed C + +/CLI reflection code is as follows:
Cppuserinfo Getuserbyid (intuserId) { //called. net method to get resultsmethodinfo^ method = Dotnetobject->gettype ()->getmethod ("Getuserbyid", BindingFlags::P ublic |bindingflags::instance); Func<int, object^>^ fun = (func<int, object^>^) delegate::createdelegate (func<int, Object^>::typeid, This-Dotnetobject, method); Object^ result =Fun (userId); //Convert managed type data to native structfunc<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")); returnuser; }
In the preceding code, it is called by a delegate method:
object^ result = Fun (userId);
Using the Sod DTO object
We got it. NET assembly method returns the Dto object, but how do I take out its data to assign to our C + + native code?
So here are 2 questions to be addressed:
1. Remove data from object objects;
2, converting and assigning data to C + + Local data structures
For the first question, we can reflect the properties of the Dto object and then correspond to the local data interface one by one, but we've already called the method in reflection, and it's complicated to reflect again.
Fortunately, our DTO interface object It is a dynamically created sod entity class object, because the sod entity class has the function of similar "dictionary", can be accessed by relevant method.
A method definition for the entity class base class:
Public Object PropertyList (string propertyfieldname)
We reflect this method and bind a delegate object to invoke it:
Staticfunc<string^, object^>^ entitycalldelegate (object^entity) { //a method definition for the entity class base class://Public Object PropertyList (string propertyfieldname)type^Base= Entity->gettype ()BaseType; MethodInfo^ Methodentity =Base->getmethod ("propertylist", BindingFlags::P ublic |bindingflags::instance); Func<string^, object^>^ funentity = (func<string^, object^>^) delegate::createdelegate (Func<String^, Object^>:: typeID,
entity, methodentity); //example string^ result = (string^) funentity ("Name"); returnfunentity; }
Then, you can use the following as follows:
func<string^, object^>^ entityprop =entityhelper::entitycalldelegate (result); int id = (int) entityprop ("ID");
To convert a. NET object to a C + + struct
In the example, we define a cppuserinfo struct:
struct cppuserinfo{ int ID; // wstring Name; CString Name; TM Birthday;};
Managed string vs. native string
This structure corresponds to the C # version of the interface Iuserinfo, but the struct members have several points to note:
CString Name;
The string type's name member, to use the string type in C + +, must contain the following header file in the C + + file:
If it is not an MFC application, include the following:
#include <atlstr.h>
Otherwise, this header file needs to be included:
#include <cstringt.h>
If you are not using CString, but wstring, then you need to define a method to implement the conversion of a managed string to a native string:
// // to use the following method, first #include <string> // static wstring marshalstring (string ^ s) { wstring os; Const wchar_t* chars = (const wchar_t*) (Marshal::stringtohglobaluni (s)) . ToPointer (); = chars; Marshal::freehglobal (IntPtr ((void*) chars)); return os; }
The above method declares a pointer of type wchar_t*, which must be freed by this pointer at the end of the method, so this form of conversion is still more cumbersome.
For a managed string conversion to a C + + native string, refer to the following 2 articles:
http://bbs.csdn.net/topics/280024331
http://blog.csdn.net/windren06/article/details/7839985
Managed date and native date data
The struct that represents the date in C + + is a TM, but it is important to note that the year portion of the TM is only able to represent the difference from 1900, so we can write the following 2 methods for a simple conversion:
static TM Convert2cppdatetime (Datetime^ DT) {TM result; Result.tm_year = dt->year-1900 = Dt->month; Result.tm_wday = Dt->day; return result; static datetime^ Covert2netdatetime ( TM cppdate) { return gcnew DateTime ( Cppdate.tm_year + 1900 , CP Pdate.tm_mon, Cppdate.tm_wday); }
With a string followed by a date type. NET and C + + conversion, basically can be used. NET DTO objects, because other numeric types can be used directly, such as the int type, as long as the type is compatible.
Converting to a native struct
Here's another look at the Object Data Transformation section within the Getuserbyid method:
// convert managed type data to native structure func<string^ , object^>^ entityprop =entityhelper::entitycalldelegate (Result); Cppuserinfo user; User.ID = (" Span style= "color: #800000;" >id ); User. Name = (string^) entityprop ( name ); // Marshalstring ((string^) entityprop (" Name "); User. Birthday = Convert2cppdatetime ((datetime^) entityprop ( " birthday ));
Now look again, using similar "dictionary" access to the Sod Dto object, to the C + + local structure conversion assignment data, it is very convenient, this is the choice of the SOD framework as C + + and. NET communication reasons.
Why not use serialization issues
In a distributed cross-platform invocation, serialization is often used as an effective means, but our application has several features:
1, there is no distributed, in the process of different language platform calls;
2, the type of deserialization is not known, because C + + does not directly reference any. NET Framework itself. NET assemblies;
3, serialization requires the use of reflection, and we are already in the reflection, will aggravate the burden;
In addition, the use of serialization also has additional work:
4, using serialization requires additional encapsulation by the called side;
5, both sides need to develop common communication protocols, and customize the serialization process, such as the common RPC framework conventions of the serialization Protocol
So, after careful consideration, I abandoned the idea of using serialization to do in-process communication with. NET in C + +.
In the next article, we'll show you how C + + and. NET Pass Collection objects.
(not to be continued)
The call is reflected in C + +. NET (ii)