1
votes

I have a specialized dictionary written in C# that takes two generic arguments. The interface is

public interface IMyDictionary<TKey, TValue> { ... }

and one of it's implementations

public MyDictionary<TKey, TValue> {...}

I also have a complicated C++ template structure which I typedef in my C++/CLI ref class:

typedef boost::some_complex_template<stuff>    MySimpleValueType;

In my C++/CLI ref class constructor, I used to create an instance of the dictionary:

MyCppCliClass::MyCppCliClass()
    : _my_dict(gcnew MyDictionary<MySimpleValueType, Something^>())
{...}

Now, if you like dependency injection, you will notice that this is bad. Ideally, I should have a constructor like this:

MyCppClass::MyCppCliClass(IMyDictionary<MySimpleValueType, Something^>^ dict){...}

This class is instantiated in C#, so now my question:

How can I instantiate this valid ref class that I am using right now outside of C++/CLI, given that (afaik) the C++ template typedef nor the pure C++ types are available in C#?

MySimpleValueType obviously must be a native type of C#, or instantiation of the Dictionary will fail:

error C3225: generic type argument for 'T1' cannot be '...', it must be a value type
> or a handle to a reference type.

I feel I should be able to define the type in the C++/CLI class (with the typedef), but instantiate the Dictionary from outside. C++/CLI typedefs are not available in C#, so maybe there is a way with a getter and type deduction of the var? Any ideas?

1
If MySimpleType is usable in that dictionary, does this mean it's actually a valid ValueType (e. g. boost::some_complex_template<stuff>::number_type that turns out to be int) ? - Medinoc
Looking at it in the debugger, it tells me it's an IMyDictionary<unsigned __int64, Something^>. But I don't think I can rely on that, as the type depends on the typedef, which in turn is dependent on various other typedefs (boost, yknow ;) ). - Wilbert
I believe your C++/CLI code will not compile if it's not a type valid for the CLR (like unsigned __int64/System::UInt64). So I guess if your code compiles, C# code can link to it. (after all, you're not actually exposing templates to other assemblies, only template instantiation results and generics) - Medinoc
Yeah, that was my conclusion too. I updated the question. I think the main problem is that typedefs I make in C++/CLI are not visible from C#. - Wilbert

1 Answers

0
votes

boost is an unmanged library. That error message is telling you that you can't use an unmanaged type in a generic managed class.

To work around this, make a managed class that will hold your unmanaged one, and use that in the container.

public ref class MySimpleValueTypeHolder
{
private:
    MySimpleValueType* unmanaged;

public:
    property MySimpleValueType* ValueType { 
        MySimpleValueType* get() { return this->unmanaged; }
    }

    MySimpleValueTypeHolder() { this->unmanaged = new MySimpleValueType(); }
    ~MySimpleValueTypeHolder() { this->!MySimpleValueTypeHolder(); }

    !MySimpleValueTypeHolder()
    {
        if(this->unmanaged != nullptr)
        {
            delete this->unmanaged;
            this->unmanaged = nullptr;
        }
    }
};

Dictionary<MySimpleValueTypeHolder^, Something^>^ foo;