如何在SWIG生成C#绑定中处理协变返回类型?
解决SWIG生成C#绑定中clone方法协变返回类型兼容早期C#版本的问题
问题背景
使用SWIG为C代码库生成C#绑定时,C中多个类的clone()方法采用协变返回类型(派生类返回自身类型),但因项目需兼容不支持协变返回的早期C#版本(如Unity常用的C# 8及以下),生成的C#代码里,派生类的clone()方法会以override修饰并返回基类类型,不符合实际需求。期望派生类的clone()方法以new修饰并返回自身类型。
解决方案
通过组合SWIG的%typemap和%csmethodmodifiers指令,无需逐个类手动修改,即可自动生成符合要求的clone()方法:
完整SWIG接口文件配置
修改你的CSharpModule.i文件如下:
%module CSharpModule %{ #include "Parent.h" #include "Child.h" %} // 为基类的clone方法设置virtual修饰符 %csmethodmodifiers Parent::clone "public virtual"; // 为所有其他类的clone方法设置new修饰符 %csmethodmodifiers *::clone "public new"; // 修改clone方法的C#返回类型为当前类名 %typemap(cstype) *::clone "$csclassname" // 自定义clone方法的C#返回值生成逻辑,确保返回当前类实例 %typemap(csout) *::clone { global::System.IntPtr cPtr = $imcall; $csclassname ret = (cPtr == global::System.IntPtr.Zero) ? null : new $csclassname(cPtr, true); return ret; } %newobject *::clone; %include "Parent.h" %include "Child.h"
效果验证
生成的Child.cs中的clone()方法会自动变为:
public new Child clone() { global::System.IntPtr cPtr = CSharpModulePINVOKE.Child_clone(swigCPtr); Child ret = (cPtr == global::System.IntPtr.Zero) ? null : new Child(cPtr, true); return ret; }
基类Parent.cs的clone()方法保持为:
public virtual Parent clone() { global::System.IntPtr cPtr = CSharpModulePINVOKE.Parent_clone(swigCPtr); Parent ret = (cPtr == global::System.IntPtr.Zero) ? null : new Parent(cPtr, true); return ret; }
原理说明
%csmethodmodifiers:控制生成的C#方法的访问修饰符和关键字,基类保留virtual,派生类使用new覆盖基类方法(符合早期C#的语法要求)。%typemap(cstype):修改C#方法的返回类型为当前类的名称($csclassname是SWIG内置变量,代表当前生成的C#类名)。%typemap(csout):自定义C#方法的返回值构造逻辑,确保返回当前类的实例而非基类实例。
内容的提问来源于stack exchange,提问作者FredericoUnO
相关产品推荐
相关产品推荐

