简体   繁体   English

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

[英]How to deal with covariant return types with SWIG for C#?

I am currently using SWIG to generate C# bindings for a third party C++ codebase.我目前正在使用 SWIG 为第三方 C++ 代码库生成 C# 绑定。 I've mostly gotten things working, but there is one thing I'm struggling with.我大部分时间都在工作,但有一件事我正在努力。 In the codebase, there is a "clone()" method in many of their classes which returns a copy of the calling object.在代码库中,它们的许多类中都有一个“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. 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 .

Is there a method within SWIG to change the return type of all "clone()" methods to match that of the class in which they reside? SWIG 中是否有一种方法可以更改所有“clone()”方法的返回类型以匹配它们所在的 class 的返回类型?

I tried using typemap with我尝试使用 typemap

%typemap(cstype) *::clone "$csclassname"

and similar variations, but received errors when trying to generate the bindings.和类似的变体,但在尝试生成绑定时收到错误。

The only "working" method I've found is to use我发现的唯一“工作”方法是使用

%ignore *::clone;

then use typemap(cscode) to redefine the clone method with the correct type for all classes that use it, but that is extremely tedious.然后使用 typemap(cscode) 为所有使用它的类重新定义具有正确类型的克隆方法,但这非常乏味。

I think I just don't completely understand how SWIG typemaps work/if they can work with specific methods like this.我想我只是不完全了解 SWIG 类型图是如何工作的/它们是否可以使用这样的特定方法。 If anyone has suggestions for a better way to do this and/or an explanation that could help clarify things for me, it would be greatly appreciated.如果有人对更好的方法提出建议和/或可以帮助我澄清事情的解释,将不胜感激。 Thank you.谢谢你。

Edit: Adjusted description to identify the problem as C# not supporting covariant return types.编辑:调整描述以将问题识别为 C# 不支持协变返回类型。

Edit 2: To clarify, C# 9.0 supports covariant return types, but earlier versions do not.编辑 2:澄清一下,C# 9.0 支持协变返回类型,但早期版本不支持。 I am using an earlier version for compatibility with a Unity project.我正在使用早期版本以与 Unity 项目兼容。 I may be able to upgrade the project and my C# version for covariant return type compatibility, though I'm not sure if SWIG's C# tool is compatible with C# 9.0.我可能能够升级项目和我的 C# 版本以实现协变返回类型兼容性,但我不确定 SWIG 的 C# 工具是否与 C# 兼容。 I wanted to check if there is a workable SWIG solution for my current C# and Unity versions before pursuing that potential option.在寻求潜在选项之前,我想检查我当前的 C# 和 Unity 版本是否有可行的 SWIG 解决方案。

Sample Code to Reproduce Issue:重现问题的示例代码:

Parent.h父.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

Parent.cpp父级.cpp

#include "Parent.h"
Parent::Parent(const Parent &copiedObject)
{
    val1 = copiedObject.val1;
}
Parent* Parent::clone() const
{
    Parent* clone = new Parent(*this);
    return clone;
}

Child.h孩子.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

Child.cpp孩子.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 CSharpModule.i

%module CSharpModule
%{
#include "Parent.h"
#include "Child.h"
%}

%newobject *::clone;
%include "Parent.h"
%include "Child.h"

clone() method in generated Child.cs生成的 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;
}

Due to lack of support for covariant return types in C#, the clone() method would need to change to "new" instead of "override (SWIG's %csmethodmodifiers directive) in the derived class:由于在 C# 中缺乏对协变返回类型的支持,因此在派生的 class 中,clone() 方法需要更改为“new”而不是“override(SWIG 的 %csmethodmodifiers 指令):

Desired clone() method所需的 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;
}

I don't know where you get your information, but your entire premise is wrong.我不知道你从哪里得到你的信息,但你的整个前提是错误的。 C# definitely supports covariant return types : C# 绝对支持协变返回类型

    abstract class B 
    {
        public abstract B Build();
    }
    
    class D : B
    {
        public override D Build() => new();
    }

That said, this feature in either language adds essentially nothing, since any "correct" OOP program will use the base class' (or interface's) methods.也就是说,这两种语言中的这个特性基本上什么都没有,因为任何“正确的” OOP 程序都将使用基类(或接口)的方法。 If you find yourself constantly down-casting to get the more specific version of the function, you should probably rethink your design.如果您发现自己一直在寻找更具体的 function 版本,您可能应该重新考虑您的设计。

After all, the code generated is identical with or without this feature.毕竟,无论有没有这个特性,生成的代码都是一样的。 This is a compile-time only feature.这是仅编译时的功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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