在 Unity3D 中,虽然主要使用 C# 进行开发,但有时你可能需要利用 C++ 代码来实现某些高性能或平台特定的功能。这时,你可以使用 Unity 的 C++ 插件机制(也称为 Native Plugins)来桥接 C# 和 C++ 代码。
创建 Unity3D C++ Bridge 的步骤
1. 创建 C++ 动态链接库(DLL)
首先,你需要创建一个 C++ 动态链接库(DLL),其中包含你希望在 Unity 中调用的函数。
示例:创建一个简单的 C++ DLL
-
创建 C++ 项目:
- 使用 Visual Studio 或其他 IDE 创建一个新的 C++ 动态链接库项目。
-
编写 C++ 代码:
- 在项目中添加一个新的 C++ 源文件(如
MyPlugin.cpp
),并编写你希望导出的函数。
- 在项目中添加一个新的 C++ 源文件(如
// MyPlugin.cpp
#include <iostream>
extern "C" {
__declspec(dllexport) void HelloWorld() {
std::cout << "Hello from C++!" << std::endl;
}
__declspec(dllexport) int Add(int a, int b) {
return a + b;
}
}
- 编译 DLL:
- 编译项目,生成 DLL 文件(如
MyPlugin.dll
)。
- 编译项目,生成 DLL 文件(如
2. 在 Unity 项目中使用 C++ DLL
-
将 DLL 文件复制到 Unity 项目:
- 将生成的
MyPlugin.dll
文件复制到 Unity 项目的Assets/Plugins
文件夹中。
- 将生成的
-
编写 C# 代码调用 C++ 函数:
- 在 Unity 项目中创建一个新的 C# 脚本(如
MyPluginWrapper.cs
),并使用DllImport
属性导入 C++ 函数。
- 在 Unity 项目中创建一个新的 C# 脚本(如
// MyPluginWrapper.cs
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class MyPluginWrapper : MonoBehaviour
{
// Import the C++ functions
[DllImport("MyPlugin")]
private static extern void HelloWorld();
[DllImport("MyPlugin")]
private static extern int Add(int a, int b);
void Start()
{
// Call the C++ functions
HelloWorld();
int result = Add(3, 4);
Debug.Log("Result of Add(3, 4): " + result);
}
}
- 测试 C# 调用 C++ 函数:
- 将
MyPluginWrapper
脚本附加到一个 GameObject 上,并运行 Unity 项目。你应该会在控制台中看到 C++ 函数的输出。
- 将
注意事项
-
平台兼容性:
- 确保你的 C++ DLL 针对目标平台进行编译。例如,Windows 使用
.dll
文件,macOS 使用.dylib
文件,Linux 使用.so
文件。 - 在 Unity 中,你可以在
Assets/Plugins
文件夹中创建子文件夹(如x86
,x86_64
,Android
,iOS
等)来存放不同平台的插件。
- 确保你的 C++ DLL 针对目标平台进行编译。例如,Windows 使用
-
函数导出:
- 使用
extern "C"
和__declspec(dllexport)
(Windows)或__attribute__((visibility("default")))
(Linux/macOS)来导出 C++ 函数。 - 确保函数名在 C++ 和 C# 中一致。
- 使用
-
内存管理:
- 注意 C++ 和 C# 之间的内存管理。避免在 C++ 中分配内存并在 C# 中释放,或反之。
-
调试:
- 调试 C++ 插件可能会比较复杂。你可以使用 Visual Studio 的附加进程功能来调试运行中的 Unity 编辑器或构建的应用。
总结
通过使用 Unity 的 C++ 插件机制,你可以在 Unity 项目中调用高性能或平台特定的 C++ 代码。按照上述步骤创建和使用 C++ DLL,可以有效地扩展 Unity 的功能。注意平台兼容性和内存管理,以确保应用的稳定性和性能。
优缺点
在 Unity3D 中使用 C++ 插件(C++ Bridge)机制可以带来许多好处,但也有一些潜在的缺点。以下是使用 Unity3D C++ Bridge 机制的优缺点:
优点
-
性能提升:
- C++ 通常比 C# 更高效,特别是在需要进行大量计算或处理复杂算法时。通过将性能关键的代码移到 C++,可以显著提升应用的性能。
-
平台特定功能:
- 有些平台特定的功能或 API 只能通过 C++ 访问。使用 C++ 插件可以让你利用这些功能,从而扩展 Unity 的能力。
-
代码重用:
- 如果你已经有现成的 C++ 库或代码,可以通过 C++ 插件机制将其集成到 Unity 项目中,避免重复开发。
-
更好的内存控制:
- C++ 提供了更细粒度的内存管理控制,可以更有效地管理内存分配和释放,减少垃圾回收带来的性能开销。
-
多语言支持:
- 通过 C++ 插件,可以将其他编程语言(如 Python、Lua)的功能集成到 Unity 项目中,利用这些语言的特性和库。
缺点
-
复杂性增加:
- 引入 C++ 插件会增加项目的复杂性。需要处理跨语言调用、内存管理、数据类型转换等问题。
-
调试困难:
- 调试 C++ 插件比调试纯 C# 代码更复杂。需要使用不同的调试工具,并且调试过程可能涉及跨语言调用的上下文切换。
-
平台兼容性:
- 需要为每个目标平台编译和维护不同的 C++ 插件版本(如 Windows 的
.dll
,macOS 的.dylib
,Linux 的.so
)。这增加了构建和发布的复杂性。
- 需要为每个目标平台编译和维护不同的 C++ 插件版本(如 Windows 的
-
部署和更新:
- 部署和更新 C++ 插件比纯 C# 代码更麻烦。需要确保所有目标平台的插件版本一致,并处理可能的兼容性问题。
-
安全性:
- C++ 代码中可能存在内存泄漏、缓冲区溢出等安全问题。需要特别注意代码的安全性和稳定性。
-
开发环境要求:
- 开发和编译 C++ 插件需要特定的开发环境和工具链(如 Visual Studio、GCC)。这可能增加开发团队的工具和环境配置成本。
适用场景
尽管有一些缺点,C++ 插件机制在以下场景中仍然非常有用:
-
性能关键的计算:
- 需要进行大量计算或复杂算法处理的场景,如物理模拟、图像处理、音频处理等。
-
平台特定功能:
- 需要访问平台特定 API 或功能的场景,如硬件加速、低级系统调用等。
-
现有 C++ 代码库:
- 已经有现成的 C++ 库或代码,希望在 Unity 项目中重用这些代码。
-
多语言集成:
- 需要将其他编程语言的功能集成到 Unity 项目中,通过 C++ 插件桥接这些语言。
总结
使用 Unity3D 的 C++ Bridge 机制可以带来性能提升、平台特定功能访问和代码重用等优点,但也会增加项目的复杂性和调试难度。根据具体需求和项目情况,权衡这些优缺点,合理选择是否使用 C++ 插件机制。
Native Plugins
“Native Plugins” 指的是在托管环境(如 .NET 或 Unity)中使用的本地代码库。这些插件通常是用 C、C++ 或其他非托管语言编写的,并通过平台调用(P/Invoke)或其他互操作技术与托管代码进行交互。
在 Unity 中,Native Plugins 通常用于以下目的:
- 性能优化:某些计算密集型任务可以在本地代码中更高效地执行。
- 访问平台特定功能:某些功能可能只能通过本地 API 访问,例如操作系统特定的功能或硬件接口。
- 重用现有库:如果已经有用 C 或 C++ 编写的库,可以通过 Native Plugins 将其集成到 Unity 项目中。
示例
假设我们有一个用 C++ 编写的库,它提供了一些数学运算功能。我们希望在 Unity 中使用这些功能。
C++ 代码(MathLibrary.cpp)
extern "C" {
__declspec(dllexport) int Add(int a, int b) {
return a + b;
}
__declspec(dllexport) int Subtract(int a, int b) {
return a - b;
}
}
C# 代码(MathLibrary.cs)
using System;
using System.Runtime.InteropServices;
public class MathLibrary
{
[DllImport("MathLibrary")]
public static extern int Add(int a, int b);
[DllImport("MathLibrary")]
public static extern int Subtract(int a, int b);
}
public class Test
{
public static void Main()
{
int result1 = MathLibrary.Add(5, 3);
int result2 = MathLibrary.Subtract(5, 3);
Console.WriteLine($"Add: {result1}");
Console.WriteLine($"Subtract: {result2}");
}
}
在这个示例中,我们定义了一个简单的 C++ 库 MathLibrary
,并通过 DllImport
属性在 C# 中调用它。DllImport
属性指定了要加载的 DLL 名称,并将 C# 方法映射到本地函数。
Unity 中的使用
在 Unity 中使用 Native Plugins 时,步骤类似:
- 编写和编译本地代码:编写 C++ 代码并编译为 DLL(在 Windows 上)或其他适当的库格式(如
.so
或.dylib
)。 - 将库添加到 Unity 项目:将编译好的库文件放入 Unity 项目的
Plugins
文件夹中。 - 编写 C# 代码进行互操作:使用
DllImport
属性在 C# 脚本中调用本地函数。
注意事项
- 平台兼容性:确保库在所有目标平台上都可用,并且正确编译。
- 内存管理:注意托管和非托管代码之间的内存管理,避免内存泄漏。
- 错误处理:处理可能的错误和异常情况,确保应用程序的稳定性。
通过使用 Native Plugins,可以在托管环境中利用本地代码的性能和功能优势。
自定义Unity3D C++Bridge代码自动化生成工具
创建一个自定义的 Unity3D C++ Bridge 代码自动化生成工具可以帮助你简化跨语言调用的过程。以下是一个基本的实现思路:
设计思路
-
输入接口定义:
- 使用一个简单的接口定义文件(如 JSON 或 XML)来描述你希望导出的 C++ 函数和类。
-
解析接口定义:
- 编写一个解析器来读取接口定义文件,并提取函数和类的信息。
-
生成 C++ 和 C# 代码:
- 根据解析出的信息,自动生成 C++ 和 C# 的桥接代码。
-
编译和集成:
- 编译生成的 C++ 代码为 DLL,并将生成的 C# 代码集成到 Unity 项目中。
实现步骤
1. 定义接口文件格式
使用 JSON 作为接口定义文件格式:
{
"functions": [
{
"name": "Add",
"returnType": "int",
"parameters": [
{"name": "a", "type": "int"},
{"name": "b", "type": "int"}
]
}
]
}
2. 编写解析器
使用 C# 编写一个简单的 JSON 解析器:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
public class FunctionDefinition
{
public string Name { get; set; }
public string ReturnType { get; set; }
public List<Parameter> Parameters { get; set; }
}
public class Parameter
{
public string Name { get; set; }
public string Type { get; set; }
}
public class InterfaceDefinition
{
public List<FunctionDefinition> Functions { get; set; }
}
public class InterfaceParser
{
public static InterfaceDefinition Parse(string filePath)
{
var json = File.ReadAllText(filePath);
return JsonConvert.DeserializeObject<InterfaceDefinition>(json);
}
}
3. 生成代码
编写代码生成器,根据解析出的信息生成 C++ 和 C# 代码:
public class CodeGenerator
{
public static void GenerateCppCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("#include <iostream>");
writer.WriteLine("extern \"C\" {");
foreach (var function in definition.Functions)
{
writer.Write($" __declspec(dllexport) {function.ReturnType} {function.Name}(");
writer.Write(string.Join(", ", function.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(") {");
writer.WriteLine(" // TODO: Implement function");
writer.WriteLine(" }");
}
writer.WriteLine("}");
}
}
public static void GenerateCSharpCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("using System;");
writer.WriteLine("using System.Runtime.InteropServices;");
writer.WriteLine("public class NativeMethods {");
foreach (var function in definition.Functions)
{
writer.WriteLine($" [DllImport(\"MyPlugin\")]");
writer.Write($" public static extern {function.ReturnType} {function.Name}(");
writer.Write(string.Join(", ", function.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(");");
}
writer.WriteLine("}");
}
}
}
4. 编译和集成
-
编译 C++ 代码:
- 使用 C++ 编译器将生成的 C++ 代码编译为 DLL。
-
集成到 Unity:
- 将生成的 C# 代码添加到 Unity 项目中,并将编译好的 DLL 放入
Assets/Plugins
文件夹。
- 将生成的 C# 代码添加到 Unity 项目中,并将编译好的 DLL 放入
5. 使用生成的代码
在 Unity 中调用生成的 C# 接口:
using UnityEngine;
public class ExampleUsage : MonoBehaviour
{
void Start()
{
int result = NativeMethods.Add(3, 4);
Debug.Log("Result of Add(3, 4): " + result);
}
}
总结
通过自定义工具,你可以自动化生成 Unity3D C++ Bridge 的代码,减少手动编码的工作量和错误。这个工具可以根据你的需求进行扩展,比如支持更多的数据类型、类的导出等。
好的,接下来我们可以进一步完善和扩展这个自定义的 Unity3D C++ Bridge 代码自动化生成工具。以下是一些可以改进和扩展的方面:
1. 支持更多的数据类型
目前的示例只支持基本的数据类型(如 int
)。我们可以扩展工具以支持更多的数据类型(如 float
、double
、string
等)。
更新接口定义文件格式
{
"functions": [
{
"name": "Add",
"returnType": "int",
"parameters": [
{"name": "a", "type": "int"},
{"name": "b", "type": "int"}
]
},
{
"name": "Multiply",
"returnType": "float",
"parameters": [
{"name": "a", "type": "float"},
{"name": "b", "type": "float"}
]
}
]
}
更新代码生成器
public class CodeGenerator
{
public static void GenerateCppCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("#include <iostream>");
writer.WriteLine("extern \"C\" {");
foreach (var function in definition.Functions)
{
writer.Write($" __declspec(dllexport) {function.ReturnType} {function.Name}(");
writer.Write(string.Join(", ", function.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(") {");
writer.WriteLine(" // TODO: Implement function");
writer.WriteLine(" }");
}
writer.WriteLine("}");
}
}
public static void GenerateCSharpCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("using System;");
writer.WriteLine("using System.Runtime.InteropServices;");
writer.WriteLine("public class NativeMethods {");
foreach (var function in definition.Functions)
{
writer.WriteLine($" [DllImport(\"MyPlugin\")]");
writer.Write($" public static extern {MapCppTypeToCSharp(function.ReturnType)} {function.Name}(");
writer.Write(string.Join(", ", function.Parameters.ConvertAll(p => $"{MapCppTypeToCSharp(p.Type)} {p.Name}")));
writer.WriteLine(");");
}
writer.WriteLine("}");
}
}
private static string MapCppTypeToCSharp(string cppType)
{
switch (cppType)
{
case "int": return "int";
case "float": return "float";
case "double": return "double";
case "char*": return "string";
// 添加更多类型映射
default: throw new NotSupportedException($"Unsupported type: {cppType}");
}
}
}
2. 支持类的导出
我们可以扩展工具以支持类的导出,包括类的成员函数和成员变量。
更新接口定义文件格式
{
"classes": [
{
"name": "MathOperations",
"methods": [
{
"name": "Add",
"returnType": "int",
"parameters": [
{"name": "a", "type": "int"},
{"name": "b", "type": "int"}
]
},
{
"name": "Multiply",
"returnType": "float",
"parameters": [
{"name": "a", "type": "float"},
{"name": "b", "type": "float"}
]
}
]
}
]
}
更新解析器
public class MethodDefinition
{
public string Name { get; set; }
public string ReturnType { get; set; }
public List<Parameter> Parameters { get; set; }
}
public class ClassDefinition
{
public string Name { get; set; }
public List<MethodDefinition> Methods { get; set; }
}
public class InterfaceDefinition
{
public List<ClassDefinition> Classes { get; set; }
}
public class InterfaceParser
{
public static InterfaceDefinition Parse(string filePath)
{
var json = File.ReadAllText(filePath);
return JsonConvert.DeserializeObject<InterfaceDefinition>(json);
}
}
更新代码生成器
生成 C++ 代码
我们需要生成类的定义和方法的实现。
public class CodeGenerator
{
public static void GenerateCppCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("#include <iostream>");
writer.WriteLine("extern \"C\" {");
foreach (var classDef in definition.Classes)
{
writer.WriteLine($" class {classDef.Name} {{");
writer.WriteLine(" public:");
foreach (var method in classDef.Methods)
{
writer.Write($" {method.ReturnType} {method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(");");
}
writer.WriteLine(" };");
foreach (var method in classDef.Methods)
{
writer.Write($" __declspec(dllexport) {method.ReturnType} {classDef.Name}_{method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(") {");
writer.WriteLine($" {classDef.Name} obj;");
writer.Write($" return obj.{method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => p.Name)));
writer.WriteLine(");");
writer.WriteLine(" }");
}
}
writer.WriteLine("}");
}
}
public static void GenerateCSharpCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("using System;");
writer.WriteLine("using System.Runtime.InteropServices;");
writer.WriteLine("public class NativeMethods {");
foreach (var classDef in definition.Classes)
{
writer.WriteLine($" public class {classDef.Name} {{");
foreach (var method in classDef.Methods)
{
writer.WriteLine($" [DllImport(\"MyPlugin\")]");
writer.Write($" public static extern {MapCppTypeToCSharp(method.ReturnType)} {classDef.Name}_{method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => $"{MapCppTypeToCSharp(p.Type)} {p.Name}")));
writer.WriteLine(");");
}
writer.WriteLine(" }");
}
writer.WriteLine("}");
}
}
private static string MapCppTypeToCSharp(string cppType)
{
switch (cppType)
{
case "int": return "int";
case "float": return "float";
case "double": return "double";
case "char*": return "string";
// 添加更多类型映射
default: throw new NotSupportedException($"Unsupported type: {cppType}");
}
}
}
3. 支持更多的特性
我们可以进一步扩展工具以支持更多的特性,例如:
- 构造函数和析构函数:支持类的构造函数和析构函数。
- 成员变量:支持类的成员变量导出。
- 命名空间:支持命名空间的导出。
更新接口定义文件格式
{
"classes": [
{
"name": "MathOperations",
"constructors": [
{
"parameters": []
}
],
"methods": [
{
"name": "Add",
"returnType": "int",
"parameters": [
{"name": "a", "type": "int"},
{"name": "b", "type": "int"}
]
},
{
"name": "Multiply",
"returnType": "float",
"parameters": [
{"name": "a", "type": "float"},
{"name": "b", "type": "float"}
]
}
],
"destructors": [
{}
]
}
]
}
更新解析器
我们需要更新解析器以支持新的接口定义文件格式。
public class ConstructorDefinition
{
public List<Parameter> Parameters { get; set; }
}
public class DestructorDefinition
{
}
public class MethodDefinition
{
public string Name { get; set; }
public string ReturnType { get; set; }
public List<Parameter> Parameters { get; set; }
}
public class MemberVariable
{
public string Name { get; set; }
public string Type { get; set; }
}
public class ClassDefinition
{
public string Name { get; set; }
public List<ConstructorDefinition> Constructors { get; set; }
public List<MethodDefinition> Methods { get; set; }
public List<DestructorDefinition> Destructors { get; set; }
public List<MemberVariable> MemberVariables { get; set; }
}
public class InterfaceDefinition
{
public List<ClassDefinition> Classes { get; set; }
}
public class InterfaceParser
{
public static InterfaceDefinition Parse(string filePath)
{
var json = File.ReadAllText(filePath);
return JsonConvert.DeserializeObject<InterfaceDefinition>(json);
}
}
更新代码生成器
我们需要更新代码生成器以支持生成构造函数、析构函数和成员变量的代码。
生成 C++ 代码
public class CodeGenerator
{
public static void GenerateCppCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("#include <iostream>");
writer.WriteLine("extern \"C\" {");
foreach (var classDef in definition.Classes)
{
writer.WriteLine($" class {classDef.Name} {{");
writer.WriteLine(" public:");
// 生成成员变量
foreach (var member in classDef.MemberVariables)
{
writer.WriteLine($" {member.Type} {member.Name};");
}
// 生成构造函数
foreach (var constructor in classDef.Constructors)
{
writer.Write($" {classDef.Name}(");
writer.Write(string.Join(", ", constructor.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(");");
}
// 生成析构函数
foreach (var destructor in classDef.Destructors)
{
writer.WriteLine($" ~{classDef.Name}();");
}
// 生成方法
foreach (var method in classDef.Methods)
{
writer.Write($" {method.ReturnType} {method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(");");
}
writer.WriteLine(" };");
// 生成构造函数实现
foreach (var constructor in classDef.Constructors)
{
writer.Write($" __declspec(dllexport) {classDef.Name}* Create{classDef.Name}(");
writer.Write(string.Join(", ", constructor.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(") {");
writer.Write($" return new {classDef.Name}(");
writer.Write(string.Join(", ", constructor.Parameters.ConvertAll(p => p.Name)));
writer.WriteLine(");");
writer.WriteLine(" }");
}
// 生成析构函数实现
foreach (var destructor in classDef.Destructors)
{
writer.Write($" __declspec(dllexport) void Destroy{classDef.Name}({classDef.Name}* obj) {{");
writer.WriteLine(" delete obj;");
writer.WriteLine(" }");
}
// 生成方法实现
foreach (var method in classDef.Methods)
{
writer.Write($" __declspec(dllexport) {method.ReturnType} {classDef.Name}_{method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => $"{p.Type} {p.Name}")));
writer.WriteLine(") {");
writer.WriteLine($" {classDef.Name} obj;");
writer.Write($" return obj.{method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => p.Name)));
writer.WriteLine(");");
writer.WriteLine(" }");
}
}
writer.WriteLine("}");
}
}
public static void GenerateCSharpCode(InterfaceDefinition definition, string outputPath)
{
using (var writer = new StreamWriter(outputPath))
{
writer.WriteLine("using System;");
writer.WriteLine("using System.Runtime.InteropServices;");
writer.WriteLine("public class NativeMethods {");
foreach (var classDef in definition.Classes)
{
writer.WriteLine($" public class {classDef.Name} {{");
// 生成构造函数
foreach (var constructor in classDef.Constructors)
{
writer.WriteLine($" [DllImport(\"MyPlugin\")]");
writer.Write($" public static extern IntPtr Create{classDef.Name}(");
writer.Write(string.Join(", ", constructor.Parameters.ConvertAll(p => $"{MapCppTypeToCSharp(p.Type)} {p.Name}")));
writer.WriteLine(");");
}
// 生成析构函数
foreach (var destructor in classDef.Destructors)
{
writer.WriteLine($" [DllImport(\"MyPlugin\")]");
writer.WriteLine($" public static extern void Destroy{classDef.Name}(IntPtr obj);");
}
// 生成方法
foreach (var method in classDef.Methods)
{
writer.WriteLine($" [DllImport(\"MyPlugin\")]");
writer.Write($" public static extern {MapCppTypeToCSharp(method.ReturnType)} {classDef.Name}_{method.Name}(");
writer.Write(string.Join(", ", method.Parameters.ConvertAll(p => $"{MapCppTypeToCSharp(p.Type)} {