[英]How to deal with covariant return types with SWIG for C#?
我目前正在使用 SWIG 為第三方 C++ 代碼庫生成 C# 綁定。 我大部分時間都在工作,但有一件事我正在努力。 在代碼庫中,它們的許多類中都有一個“clone()”方法,該方法返回調用 object 的副本。 The method uses covariant return types in the C++ code to return an object of the given class's type, but, due to C# not supporting covariant return types, the return types of the clone methods in the generated C# code are all that of the base class .
SWIG 中是否有一種方法可以更改所有“clone()”方法的返回類型以匹配它們所在的 class 的返回類型?
我嘗試使用 typemap
%typemap(cstype) *::clone "$csclassname"
和類似的變體,但在嘗試生成綁定時收到錯誤。
我發現的唯一“工作”方法是使用
%ignore *::clone;
然后使用 typemap(cscode) 為所有使用它的類重新定義具有正確類型的克隆方法,但這非常乏味。
我想我只是不完全了解 SWIG 類型圖是如何工作的/它們是否可以使用這樣的特定方法。 如果有人對更好的方法提出建議和/或可以幫助我澄清事情的解釋,將不勝感激。 謝謝你。
編輯:調整描述以將問題識別為 C# 不支持協變返回類型。
編輯 2:澄清一下,C# 9.0 支持協變返回類型,但早期版本不支持。 我正在使用早期版本以與 Unity 項目兼容。 我可能能夠升級項目和我的 C# 版本以實現協變返回類型兼容性,但我不確定 SWIG 的 C# 工具是否與 C# 兼容。 在尋求潛在選項之前,我想檢查我當前的 C# 和 Unity 版本是否有可行的 SWIG 解決方案。
重現問題的示例代碼:
父.h
#ifndef PARENT_H
#define PARENT_H
class Parent
{
public:
int val1;
Parent::Parent() = default;
Parent::Parent(const Parent &copiedObject);
virtual Parent* clone() const;
};
#endif
父級.cpp
#include "Parent.h"
Parent::Parent(const Parent &copiedObject)
{
val1 = copiedObject.val1;
}
Parent* Parent::clone() const
{
Parent* clone = new Parent(*this);
return clone;
}
孩子.h
#ifndef CHILD_H
#define CHILD_H
#include "Parent.h"
class Child : public Parent
{
public:
int val2;
Child::Child() = default;
Child::Child(const Child &copiedObject);
Child* clone() const override;
};
#endif
孩子.cpp
#include "Child.h"
Child::Child(const Child &copiedObject) : Parent(copiedObject)
{
val1 = copiedObject.val1;
val2 = copiedObject.val2;
}
Child* Child::clone() const
{
Child* clone = new Child(*this);
return clone;
}
CSharpModule.i
%module CSharpModule
%{
#include "Parent.h"
#include "Child.h"
%}
%newobject *::clone;
%include "Parent.h"
%include "Child.h"
生成的 Child.cs 中的 clone() 方法
public override Parent clone() {
global::System.IntPtr cPtr = CSharpModulePINVOKE.Child_clone(swigCPtr);
Child ret = (cPtr == global::System.IntPtr.Zero) ? null : new Child(cPtr, true);
return ret;
}
由於在 C# 中缺乏對協變返回類型的支持,因此在派生的 class 中,clone() 方法需要更改為“new”而不是“override(SWIG 的 %csmethodmodifiers 指令):
所需的 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;
}
我不知道你從哪里得到你的信息,但你的整個前提是錯誤的。 C# 絕對支持協變返回類型:
abstract class B
{
public abstract B Build();
}
class D : B
{
public override D Build() => new();
}
也就是說,這兩種語言中的這個特性基本上什么都沒有,因為任何“正確的” OOP 程序都將使用基類(或接口)的方法。 如果您發現自己一直在尋找更具體的 function 版本,您可能應該重新考慮您的設計。
畢竟,無論有沒有這個特性,生成的代碼都是一樣的。 這是僅編譯時的功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.