【问题标题】:Single C++/CLI method to wrap many type specific C functions单个 C++/CLI 方法来包装许多类型特定的 C 函数
【发布时间】:2011-01-06 14:28:30
【问题描述】:

我正在使用 C++/CLI 包装一个 C 库,以便可以在 C# 中以 C# 的方式轻松使用 C 库。

这个库中的一些函数用于将值放入容器中。 C 中没有泛型,因此每个类型都有一个函数 CLIB_SetBool(BOOL value)、CLIB_SetInt(int value)、CLIB_SetString(char* string) 等等。

为了让 C# 更易于使用,我创建了一个单独的 Set 函数,它采用 System::Object。

我有两个相关的问题:

  1. 使用我的方法,您将如何在 System::Object 类型上使用 switch 语句来调用正确的 CLIB_Setxxxx 函数。 [typeid 仅适用于非托管代码,我似乎无法使用 GetType。]

  2. 有没有更好的方法来包装这些函数,比如使用泛型? [我开始使用模板特化,但后来意识到 C# 看不到模板。]

谢谢。

编辑

如何实现 void Set(System::Object^ value) ?

我想做这样的事情:

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
}
}

托管代码的 typeid 失败,显然这些案例无效。如何解决?

【问题讨论】:

  • 不是简单的重载吗?
  • 我同意亚历山大的观点;最安全和最透明的方法是简单地为每个函数调用编写一个包装器作为一组重载。
  • 从 C# 我想要放置一个 System::Object (我正在使用 devexpress 容器),所以我的一个重载将是 Set(System::Object^ value),它就是这个函数我不知道如何(语法)实现。 +1 亚历山大 C
  • 同意三个。它也快了很多。

标签: c# c c++-cli


【解决方案1】:

您可能会比使用按类型键控的委托字典更糟糕(抱歉,C# 语法,我已经有一段时间没有使用 C++/CLI 了)。当然,在每个委托中,您都实际调用了相应的 C 函数。

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

【讨论】:

  • 感谢您的帮助。我真的在寻找一个 C++/CLI 解决方案,其中查找是静态完成的(以获得更好的性能)。我只是不知道如何将 System::Object 的类型与 case 语句中所有支持的类型进行比较。
  • @T33C: if (o is int) ... else if (o is string) else ...
  • @leppie,我省略了对 C 函数的实际调用。在某些时候,无论他使用什么方法,他都必须将托管类型转换为非托管类型,对吧?
  • @moo-juice:是的,除非有其他形式的魔法可以发挥作用,比如通过转换动态创建通用包装器。
  • @moo-juice:实际上,如果您从“通用”方法(带有对象参数)中调用正确的方法,那么您所说的内容可能会奏效。我真的看不出有什么问题。此外,只需直接调用委托,而不是使用 Invoke,例如:dict[_object.GetType()](_object)。 (澄清后+1,您可能希望将其添加到您的答案中)
【解决方案2】:

下面的一些重载呢..

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);
        }
    }
};

显然,您需要在其中进行一些转换,并为 String -> char* 转换进行适当的编组,但您明白了。

已编辑以包括类型检测

【讨论】:

【解决方案3】:

我不能使用开关,因为托管代码似乎没有像 C++ 中那样的类型的完整表示。

以下工作。

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
}

【讨论】:

  • +1:只是在提供我自己的答案之前扫描回复,这就是我应该这样做的方式。
猜你喜欢
  • 1970-01-01
  • 2016-12-29
  • 1970-01-01
  • 1970-01-01
  • 2011-09-04
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多