繁体   English   中英

如何使用 SWIG 处理 C# 的协变返回类型?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM