簡體   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