Reputation: 4429
I am wrapping a C library using C++/CLI so that the C library can be used easily from C# in a C#'ish way.
Some of the functions in this library are for putting a value into a container. There are no generics in C so there exists a function per type CLIB_SetBool(BOOL value), CLIB_SetInt(int value), CLIB_SetString(char* string) and so on.
To make it easier to use from C#, I have created a single Set function which takes a System::Object.
I have two related questions:
With my method how would you use a switch statement on the type of System::Object to call the correct CLIB_Setxxxx function. [typeid is only for unmanaged code and I can't seem to use GetType.]
Is there a better way to wrap these functions like using a Generic? [I started using template specialisation but then realised that C# doesn't see templates.]
Thanks.
EDIT
How do I implement void Set(System::Object^ value) ?
I want to do something like:
void MyWrapper::Set(System::Object^ value)
{
switch(typeid(value))
{
case System::Int32: CLIB_SetInt(MyMarshal<clib_int>(value)); break;
case System::Double: CLIB_SetInt(MyMarshal<clib_double>(value)); break;
//and so on
}
}
The typeid fails for managed code and clearly the cases are invalid. How to fix?
Upvotes: 2
Views: 890
Reputation: 4429
I can't use a switch because there doesn't seem to be an integral representation of type for managed code as there is in C++.
The following works.
void MyWrapper::Set(System::Object^ value)
{
if (value->GetType() == System::Int32::typeid)
{
CLIB_SetInt(MyMarshal<clib_int>(value));
}
else if ((value->GetType() == System::Double::typeid)
{
CLIB_SetDouble(MyMarshal<clib_double>(value));
}
//etc
}
Upvotes: 1
Reputation: 37500
What about some overloads as follows..
ref class CLIB_Wrapper
{
static void Set(System::Boolean^ value) { CLIB_SetBool(*value); }
static void Set(System::Int32^ value) { CLIB_SetInt(*value); }
static void Set(System::String^ value) { CLIB_SetString(*value); }
static void Set(System::Object^ value)
{
System::Type^ type = value->GetType();
if( type == System::Boolean::typeid )
{
Set((System::Boolean^)value);
}
else if( type == System::Int32::typeid )
{
Set((System::Int32^)value);
}
else if( type == System::String::typeid )
{
Set((System::String^)value);
}
}
};
Obviously you'll need some conversions in there with appropriate marshalling for the String -> char* conversion, but you get the idea.
Edited to include detection of type
Upvotes: 2
Reputation: 38810
You could do worse than utilize a dictionary of delegates, keyed by type (Sorry for C# syntax, it's been a while since I did C++/CLI). Within each delegate, of course, you make your actual call to the appropriate C function.
public delegate void CLIBDelegate(object);
// handlers for types that will call the appropriate CLIB_XXX function:
public void CLIB_int(object _obj);
public void CLIB_string(object _obj);
// etc...
// Our dictionary:
Dictionary<System.Type, CLIBDelegate> dict = new Dictionary<System.Type, CLIBDelegate>();
dict[typeof(System.Int32)] = CLIB_int;
dict[typeof(System.string] = CLIB_string;
// etc...
// your set function
void Set(Object _object)
{
if(dict.ContainsKey(_object.GetType())
dict[_object.GetType()](_object);
} // eo Set
Upvotes: 2