Typedefs, C++/CLI, C# + dependency injection - c#

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?

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;

Related

Calling overloaded C# array access from unmanaged C++/CLI

I have a C# project which has overridden the array access ([]) like so:
Foo.cs:
public override FooItem this[long index] {
...
The project is compiled into a .dll which is referenced by my C++/CLI project.
I have an unmanaged C++/CLI class, FooAccess:
FooAccess.h:
class FooAccess : NativeCPPClass { // not ref class
private:
gcroot<CSDll::Foo^> myFoo;
public:
void Accessor();
In FooAccess.cpp:
void FooAccess::Accessor() {
myFoo->[0]; // doesn't work
myFoo[0]; // doesn't work
pin_ptr<FooItem^> p = &myFoo[0]; // doesn't work
I am stumped.
Note that I am not allowed to edit the C# project and the C++/CLI class cannot be a ref class since it inherits from a native class.
The gcroot template makes the syntax clumsy. You have to cast to convince it to spit out the object reference, ((Foo^)myFoo)[0]. Ugh. The readable way is to lift the object reference out of the template explicitly:
void FooAccess::Accessor() {
Foo^ obj = myFoo;
FooItem^ value = obj[0];
//...
}
But you can write it directly by using the default keyword:
FooItem^ value = myFoo->default[0];
Do consider encapsulation instead of inheritance, storing a private NativeCPPClass* in a ref class, helps you avoid the high cost and awkwardness of gcroot.

Returning Managed C# List to Unmanaged C++ code

I have a C# dll ( for which register for COM interop option is set).
This C# dll has the below interface and class
interface IMyInterface
{
bool IsNameExists(string name);
List<string> GetNameList();
}
public class MyClass : IMyInterface
{
public bool IsNameExists(string name)
{
//DO Something
}
public List<string> GetNameList()
{
// DO something
}
}
I need to call the methods IsNameExists and GetNameList from unmanaged C++.
#import "..\..\ProdCon\bin\ProdCon.tlb" raw_interfaces_only
void main()
{
HRESULT hr =::CoInitialize(NULL);
IMyInterface pIMyInterface(__uuidof(MyClass));
VARIANT_BOOL bRet = FALSE;
BSTR bstrName = ::SysAllocString(_T("RAJESH"));
hr = pIMyInterface->IsNameExists(bstrName,&bRet);
}
So I created COM object as above and called the IsNameExists mehtod without any issue.
Since GetNameList method returns list, I am getting the below warning
'MyDll.IMyInterface.GetNameList(#0), MyDll'. Warning: Type library
exporter encountered a generic type instance in a signature. Generic
code may not be exported to COM.
Please help me how to return C# list to unmanaged C++ code. So that unmanaged C++ code can use this list.
'Generic code may not be exported to COM.' => hence its the type parameter string in public List GetNameList(). Thus essentially you need access to a non-generic c# method to get the data.
If you have control of the MyClass codebase you could (for example) add a:
public string[] GetNameArray()
{
return GetNameList.ToArray();
}
If not then you'll need to write a proxy/wrapper class to do something similar to the above and expose that via COM, either as a one off or a 'general' methodology using reflection say.
See for example http://weblog.west-wind.com/posts/2007/Jul/10/Generics-and-COM-Interop-dont-mix

Return dynamic object in C++/CLI to C#

I've got a C++/CLI project that wraps a large number of classes - and the classes have their own meta-data system. So I'd like to return a dynamic object to make some use cases easy in C#. But I don't see how to do this in C++.
In C# I can write the following:
dynamic TestThisOut()
{
return null;
}
void mork()
{
var d = TestThisOut();
d.Fork();
}
I would like to write TestThisOut() in C++/CLI, so that I can use it exactly the same way as I do in the "mork" function above (i.e. not having to type the dynamic keyword). Is this possible?
You can create a dynamic object in c++/cli, you just can't consume it there as you would in C# project. However you can consume it from C#. Here is how you do it:
In C++/CLI create a property or a method that returns Object^. Mark this property or method with System::Runtime::CompilerServices::DynamicAttribute. You are good to go.
Here is a quick sample I created:
namespace ClassLibrary1
{
using namespace System;
using namespace System::Dynamic;
public ref class Class1 : public DynamicObject
{
public:
[System::Runtime::CompilerServices::Dynamic]
static property Object^ Global
{
public:
Object^ get()
{
return gcnew Class1();
}
}
public:
String^ Test()
{
return "Test";
}
};
}
And my C# consumer:
Console.WriteLine( ClassLibrary1.Class1.Global.Test() );
dyanmic is C# 4.0 keyword. It is not supported in C++ CLI (and also in VB.NET).
If you want to consume dynamic object in C++ CLI, then you can use impromptu-interface library. List of supported options. Information is from this question

Does C++ have some analog of C# Type thing to store Types of classes in list / array?

In C# i can create such List to store class types:
List<Type> types_list = new List<Type>();
types_list.add(typeof(int));
types_list.add(typeof(Process)); //and etc
can i do the same in C++?
See typeid and type_info.
Note that you can not use the type_info class to create new instances of the type it represents, as C++ have no support for that.
You can store a type list with boost MPL.
Example:
#include <boost mpl stuff>
int main()
{
typedef boost::mpl::vector<char, int> types;
typedef boost::mpl::push_back<types, Process>::type newTypes;
boost::mpl::at_c<newTypes, 2>::type objectOfTypeProcess;
}
You really shouldn't use this library unless you know what you're doing, so my example isn't that specific. You might have to spend some time to get used to mpl anyway.
It is also possible to create instances dynamically. Inspiring but incomplete code:
class TypeProxy {
public:
virtual ~TypeProxy() = default;
char* create_default() const { return this->create_default_impl(); }
template <typename T>
static scoped_ptr<TypeProxy> CreateProxy ();
private:
virtual void* create_default_impl() const = 0;
};
// A creator class.
template <typename T>
class Concrete : public TypeProxy {
void *create_default_impl() const {
return new T ();
}
};
// Method to create creator proxies.
template <typename T>
scoped_ptr<TypeProxy> TypeProxy::CreateProxy () {
return scoped_ptr<TypeProxy> (new Concrete<T>());
}
Note that this is just some untested scratch code to show the operational mode. Whether to use scoped_ptr is debatable.
You can get more fancy with variadic templates (see e.g. the emplace[_(front|back)] functions in C++11), but it will become complicated as virtual function templates are not allowed, but you somehow have to pass over argument lists nevertheless.
(sidenote: boost::shared_ptr use a similar virtual/template mix, which is why you can use non-polymorphic base classes and custom deleters with it)

How to import and use a unmanaged C++ class from C#?

I have an native C++ dll, some header files and the import library. Is there a way how to instantiate an object within C# that is defined in the dll?
The two ways I'm aware of are:
to wrap the C++ code into COM
to use DLLImport and external C functions
C++/CLI is your friend for this. You'll run into one problem though: it is not possible to store standard C++ objects inside C++/CLI ref or value classes (the ones for .NET). So you'll have to resort to the following class (that you can modify) that I use in production code:
#pragma once
#include <boost/shared_ptr.hpp>
template <typename T>
ref class Handle
{
boost::shared_ptr<T>* t;
!Handle()
{
if (t != nullptr)
{
delete t;
t = nullptr;
}
}
~Handle() { this->!Handle(); }
public:
Handle() : t(new boost::shared_ptr<T>((T*)0)) {}
Handle% operator=(T* p)
{
if (p != t->get()) t->reset(p);
return *this;
}
static T* operator&(Handle% h) { return h.t->get(); }
static boost::shared_ptr<T> operator->(Handle% h) { return *h.t; }
T& reference() { return *t->get(); }
T const& const_reference() { return *t->get(); }
};
Usage: Handle<MyCppClass>^ handle; inside a C++/CLI class. You then implement stub methods, forwarding them to the handle member. Garbage collected objects will call destructors of the C++ class instance iff there is no more pointer to it:
public ref class Foo
{
void bar() { handle->bar(); }
internal:
Handle<CppNamespace::Foo>^ handle;
};
I think that your option is only build a C++/CLI class wrapper (so you can reference it like a c# class), otherwise you can't instantiate a c++ class (unmanaged) from c# code.
Alternative could be the "ugly" way: instantiate the c++ class through a c function, but you'll treat the class as a void pointer inside the c# code, so you basically will not do anything with it (except if you create other functions to interact with this class; only C functions)
C# understands C, if you want make it understand C++ you have to use C++/CLI
P.S.
C# has some basic understanding of C++ classes, but it's only about converting class data (I mean bytes: fields) into some usable data in C# (there are some Attributes), but will not allow to work with methods and things like that (avoid totally is my suggestion).

Categories

Resources