0

I've created a little demo for myself to practice combining C++ & C# (a very desirable skill for me).
It looks like this:

Class Diagram

The issue arises from the fact that the class Person has a member of type Name.
What would be the correct way to expose these classes to C#?

For example how would I expose this constructor:

    Person(Name name);

It's kind of hard to explain but the issue is that this Person constructor accepts a Name object which is native, and I can't create this native object in C# and just pass it in the constructor, right? It wouldn't even be desirable.
And even if I write a wrapper for it (say ManagedName) I can't pass it to Person since there's no acceptable constructor.

How should I cope with this situation?

Here are the headers as requested:

Nullable: http://pastebin.com/z7zTCrAq
Name: http://pastebin.com/ALNp5c1a
Person: http://pastebin.com/nkWyUv9C

MasterMastic
  • 20,711
  • 12
  • 68
  • 90
  • Have you considered C++/CLI? – bbosak Jun 10 '13 at 02:41
  • @IDWMaster Yes but this is a design issue. How would C++/CLI let me cope? – MasterMastic Jun 10 '13 at 02:42
  • A pretty grungey way is to use COM. Make an interface for your classes and call COM methods dynamically on them from C#. – paddy Jun 10 '13 at 02:43
  • @paddy Is there another solution? I don't know COM at all. – MasterMastic Jun 10 '13 at 02:46
  • Hmmm... COM versus C++/CLI. Choose the lesser of two evils. They're both horrendous, if you ask me, but I personally prefer COM because it tends to be easier to integrate into existing code. – paddy Jun 10 '13 at 02:54
  • @paddy I have 2 questions if that's okay. **1)** Does COM have to be registered / leaves artifacts etc.? **2)** How's the performances compared to C++/CLI or C interface? – MasterMastic Jun 10 '13 at 02:58
  • I'm Ken, too. Would you mind to provide some code? – Ken Kin Jun 10 '13 at 03:05
  • @Ken I can't offer too much help, as I'm learning this stuff myself. I expose my interfaces as `IDispatch*`, without registering or using GUIDs, and use runtime binding to call them. [This link](http://stackoverflow.com/questions/16312837/failed-to-cast-result-of-marshal-getactiveobject-for-com-interop-wrapper) is my own rather lame question on the subject when I was grappling with it. – paddy Jun 10 '13 at 03:05
  • @paddy: Your comment came to my Inbox .. – Ken Kin Jun 10 '13 at 03:08
  • @KenKin Another Ken <3. I'm putting the headers (the important stuff) right now (links to Pastebin at the bottom). – MasterMastic Jun 10 '13 at 03:12

1 Answers1

1

Here's one way to do it (C++/CLI)


class Name {
public:
    std::string firstName;
    std::string middleName;
    std::string lastName;
};
ref class ManagedName {
internal:
    Name* nameptr;
public:

    ManagedName() {
        nameptr = new Name();
    }
    ManagedName(System::IntPtr ptr) {
        nameptr = (Name*)(void*)ptr;
    }
    property System::String^ firstName {
        System::String^ get() {
            return gcnew System::String(nameptr->firstName.data());
        }
        void set(System::String^ val) {
            System::IntPtr strptr = System::Runtime::InteropServices::Marshal::StringToBSTR(val);
            nameptr->firstName = (char*)(void*)strptr;
            System::Runtime::InteropServices::Marshal::FreeBSTR(strptr);
        }
    };
    property System::String^ middleName {
        System::String^ get() {
            return gcnew System::String(nameptr->middleName.data());
        }
        void set(System::String^ val) {
            System::IntPtr strptr = System::Runtime::InteropServices::Marshal::StringToBSTR(val);
            nameptr->middleName = (char*)(void*)strptr;
            System::Runtime::InteropServices::Marshal::FreeBSTR(strptr);
        }
    };
    property System::String^ lastName {
        System::String^ get() {
            return gcnew System::String(nameptr->lastName.data());
        }
        void set(System::String^ val) {
            System::IntPtr strptr = System::Runtime::InteropServices::Marshal::StringToBSTR(val);
            nameptr->lastName = (char*)(void*)strptr;
            System::Runtime::InteropServices::Marshal::FreeBSTR(strptr);
        }
    };
};
class Person {
public:
    Name* name;
    std::string birthday;
    Person(Name* name) {
        this->name = name;
    }
};
ref class ManagedPerson {
public:
    ManagedPerson(ManagedName^ name) {
        //create an instance of the native class
        personPtr = new Person(name->nameptr);

    }
    property System::String^ Birthday {
        System::String^ get() {
            return gcnew System::String(personPtr->birthday.data());
        }

    };
    property ManagedName^ Name {
        ManagedName^ get() {
            return gcnew ManagedName(System::IntPtr(personPtr->name));
        }
    };
private:
    Person* personPtr;
};

bbosak
  • 5,353
  • 7
  • 42
  • 60