我正在用 C# 开发使用 c++ lib 文件的游戏编辑器。我想要 C# 中 C++ 类的 RTTI。是否可以在 C# 中获得 C++ 类的 RTTI?如果是怎么办?
2 回答
您不能将本机 C++ 类型或代码直接公开给 .NET 平台。
然而,有三种方式可以与来自 .NET(在 C#、VB.Net 或其他语言中)的“本机”C 和 C++ 代码进行交互。
- 通讯
- P/调用
- 命令行/C++
COM 可能是 .NET 方面最容易使用的。只需将 COM 对象作为参考添加到您的 .NET 项目中,然后开始与接口和类进行交互。有关在 .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++ 代码通过委托调用回 C# 等等。
过去,我构建了使用 P/Invoke 调用 DLL 中公开的函数的游戏引擎工具。您只需要小心管理本机资源即可。在这里,IDisposable 接口和类终结器成为您的朋友。例如:
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 有一个缺点。首先,它可以为本地调用增加显着的编组开销(尽管有一些方法可以加快速度)。它还需要 gameengine.dll 中的 C API。如果您的引擎是 C++ 类,则必须为 C++ 类提供 C API。这可能会增加大量工作(或需要代码生成器)。
我不会详细介绍处理将托管对象/数据编组到本机代码和从本机代码传出的所有混乱细节。只要知道它是可以做到的,而且 MSDN 是你的朋友。
将本机 C++ 代码公开给 .NET 的第三种可能也是最好的方法是通过 CLI/C++ 混合模式程序集。CLI/C++ 让您可以在一个程序集中将本机代码和托管代码相当无缝地混合在一起。
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
本文介绍了该过程。
运行时类型标识 (RTTI) 允许在程序执行期间确定对象的类型。C# 包括三个支持运行时类型识别的关键字:is、as 和 typeof。
您用于is
确定对象是否属于您想要的类型:
if (myVariable is string)
{
// do stuff
}
您用于as
从一个对象转换为另一个对象。如果不存在转换,则null
返回。
string myString = myVariable as string;
if (myString != null)
{
// do stuff
}
您用于typeof
获取有关类型的信息。
要获取表达式的运行时类型,可以使用 .NET Framework 方法GetType。