paleozogt
paleozogt

Reputation: 6563

C# SWIG vector<string> to string[]

Given C++ methods like

std::vector< std::string > getFoo();
void setFoo( const std::vector< std::string > &foo);

How can I get SWIG to expose it like this to C#

string[] getFoo();
setFoo(string[] foo);

I realize that lots of people have asked about vector<string> and SWIG, but I haven't seen anything addressing the conversion to/from string[]. Everyone mentions using the SWIG templates, like this

%template(StringVector) vector<string>;

But that just creates a datatype that callers will have to know to marshal manually. Ideally, a caller would only have to deal with string[] and let the SWIG layer figure it out.

How can I simply use string[] in C# but have it turn into vector<string> in C++?

Upvotes: 2

Views: 3080

Answers (1)

paleozogt
paleozogt

Reputation: 6563

One approach could be to add implicit casting to the SWIG-generated StringVector, so that it would be able to cast itself to/from string[].

I tried doing this via a typemap, but couldn't make it work. However, it can be done with partial classes.

It looks something like this. In SWIG,

%include std_vector.i
%include std_string.i

/* allow partial c# classes */
%typemap(csclassmodifiers) SWIGTYPE "public partial class"

/* generate template around vector<string> */
%template(StringVector) std::vector< std::string >;

Then in C#, create a partial version of StringVector:

public partial class StringVector: IDisposable, System.Collections.IEnumerable
#if !SWIG_DOTNET_1
    , System.Collections.Generic.IList<string>
#endif
{
    // cast from C# string array
    public static implicit operator StringVector(string[] inVal) {
        var outVal= new StringVector();
        foreach (string element in inVal) {
            outVal.Add(element);
        }
        return outVal;
    }

    // cast to C# string array
    public static implicit operator string[](StringVector inVal) {
        var outVal= new string[inVal.Count];
        inVal.CopyTo(outVal);
        return outVal;
    }
}

This allows you to write C# code that looks like this:

string[] foo= mymodule.getFoo();
string[] thenewfoo= { "one", "two", "three" };
mymodule.setFoo(thenewfoo);

It's still StringVector in the C# method signatures, but since the client coder can just use string[] it doesn't really matter.

Upvotes: 3

Related Questions