我正在使用 C++ lib 文件使用 C# 开发游戏编辑器。 我想要 C# 中 C++ 类的 RTTI。 是否可以在C#中获取C++类的RTTI? 如果是的话怎么办?
最佳答案
您不能直接向 .NET 平台公开 native C++ 类型或代码。
但是,可以通过三种方式与 .NET 中的“ native ”C 和 C++ 代码(C#、VB.Net 或其他形式)进行交互。
- COM
- P/调用
- CLI/C++
COM 可能是 .NET 方面最容易使用的。只需将 COM 对象作为引用添加到您的 .NET 项目中,然后开始与接口(interface)和类进行交互。有关 .NET 中与 COM 交互的更多详细信息,请阅读如下书籍:
http://www.amazon.com/NET-COM-Complete-Interoperability-Guide/dp/067232170X
这当然要求您将游戏引擎对象公开为 COM 对象。这并非易事。
下一个最容易使用的是 P/Invoke。如果您的游戏代码使用 C 调用约定打包在标准 Windows DLL 中,您可以使用 P/Invoke 访问该 DLL 中的函数。例如:
public static class UserDll
{
[DllImport("user32.dll")]
private static extern bool FlashWindow(IntPtr hwnd, bool bInvert);
public static void FlashWindow(System.Windows.Forms.Form window)
{
FlashWindow(window.Handle, false);
}
}
您可以使用 P/Invoke 做很多事情。甚至让您的 C/C++ 代码通过委托(delegate)回调到 C# 中。
我过去构建过使用 P/Invoke 来调用 DLL 中公开的函数的游戏引擎工具。您只需要小心本地资源的管理即可。在这里,IDisposable 接口(interface)和类终结器成为您的 friend 。例如:
public class Player : IDisposable
{
private IntPtr _thePlayer;
public Player()
{
_thePlayer = CreatePlayer();
}
~Player()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (disposing)
{
// dispose of managed objects (ie, not native resources only)
}
if (_thePlayer != IntPtr.Empty)
{
DestroyPlayer(_thePlayer);
_thePlayer = IntPtr.Empty;
}
}
[DllImport("gameengine.dll")]
private static extern IntPtr CreatePlayer();
[DllImport("gameengine.dll")]
private static extern void DestroyPlayer(IntPtr player);
}
使用 P/Invoke 有一个缺点。首先,它会给 native 调用增加大量的编码开销(尽管有一些方法可以加快速度)。它还需要 gameengine.dll 中的 C API。如果您的引擎是 C++ 类,则必须为 C++ 类提供 C API。这可能会增加大量工作(或需要代码生成器)。
我不会更详细地讨论处理与 native 代码之间的编码托管对象/数据的所有困惑细节。只需知道这是可以做到的,而且 MSDN 是您的 friend 。
向 .NET 公开 native C++ 代码的第三种(可能是最好的)方法是通过 CLI/C++ 混合模式程序集。 CLI/C++ 允许您在单个程序集中相当无缝地混合 native 代码和托管代码。
CLI/C++ 有一个有趣的语法,但如果您是一名 C++ 程序员,那么适应它并不难。一个例子可能是这样的:
using namespace System;
// CLI/C++ "managed" interface
interface class IDog
{
void Bark();
};
#pragma managed(push off)
// Native C++
class Pet
{
public:
Pet() {}
~Pet() {}
const char* GetNativeTypeName()
{
return typeid(Pet).name();
}
};
#pragma managed(pop)
// CLI/C++ "managed" class
ref class Dog : IDog
{
private:
Pet* _nativePet;
public:
Dog()
: _nativePet(new Pet())
{}
~Dog()
{
delete _nativePet;
_nativePet = 0;
}
void Bark()
{
// Managed code talking to native code, cats & dogs living together, oh my!
Console::WriteLine("Bow wow wow!");
Console::WriteLine(new System::String(_nativePet->GetNativeTypeName()));
}
};
void _tmain()
{
Dog^ d = gcnew Dog();
d->Bark();
}
我的建议(已经完成了您想要做的事情)是,对于超过中等复杂程度的任何事情,最好的解决方案是尝试为您的游戏引擎提供 CLI/C++ API。我从 MSDN 上学到了有关 CLI/C++ 的所有知识,但我听说如果您喜欢内容丰富的书,这本书会很不错。
http://www.amazon.com/Expert-Visual-CLI-Programmers-Experts/dp/1590597567
关于c# - C# 应用程序中的 C++ lib RTTI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2721633/