Short, direct answers for a Go developer or a C# developer meeting go2cs for the first time. Each answer links to the page that has the detail. The limits are collected in Limitations, and specific bugs with their workarounds are in Known issues.
Mostly to use Go code from inside .NET. When the library you need is written in Go, the usual choices are a separate process, a native wrapper, or a hand rewrite that has to be kept in step forever. go2cs adds another: convert it, and call it as managed code. Converted code is also a way to run a Go program anywhere .NET runs, and because the C# mirrors the Go, a way to learn one language from the other. Background has the longer answer.
If you write Go and have no .NET in your life, go2cs gives you nothing Go does not already do better. It is for the place where the two meet.
Usually, yes. Most compute lands within a small multiple of Go's time, string-heavy work takes several times longer, and maps run at parity with Go or better. Asking at run time whether a value satisfies an interface is the slowest thing converted code does. A converted program also starts slower and uses more memory than the Go it came from. The performance comparison has the measurements and says which machine and platform produced them. Some optimization is already in, such as stack strings and stack slices, and the Roadmap lists the work planned to narrow the gap.
That is measured, not claimed. Each standard-library package's own Go test suite is converted to C#, run,
and compared with go test, verdict for verdict, on Windows and Linux. A difference is never hidden: it
is disclosed by name, with its reason, on the package's row in
Validated Test Packages.
What "validated" means, and what it doesn't
says what that proves.
Some things do differ, and you should know them before you start. A goroutine is an operating-system thread, so thousands are fine and hundreds of thousands are not. A deadlock usually hangs where Go would report it. A goroutine's stack does not grow. What converts, but doesn't behave exactly like Go lists them all.
- cgo. A package that imports
"C"is refused, by name, and the run stops (the plan). - Hand-written assembly. A function whose body lives in a
.sfile becomes a stub that throws when it is called. Many libraries ship a pure-Go fallback behind a build tag, and converting with that tag is the usual answer. - Code that needs a newer Go than go2cs tracks. The converter refuses it and names both releases.
- One form of generic type alias, an alias of an anonymous struct or interface.
What won't make the trip has the detail and the workarounds.
Exactly one Go release and one .NET release at a time, both named in the README's Requirements. The Go release it tracks today is out of upstream support, so the converted standard library carries none of the Go security fixes issued since. The Roadmap says which Go releases come next and in what order.
Windows and Linux on x64, where the converted standard library is validated against Go's own tests. macOS, on Intel and Apple silicon, has packages and is being validated package by package; a row on the roster shows a macOS count once its package validates there. One conversion targets one operating system, so you convert once for each. Platforms has the rest.
Like the Go, on purpose. A Go method is a C# extension method, multiple results are a tuple, and an
embedded struct's fields are promoted. Names keep Go's spelling, so they do not follow .NET naming
conventions, and a few Go ideas with no C# spelling use letters you will not find on your keyboard, such
as ж<T> for a pointer. The glyph table
explains each one. To judge it on real code, see
Real standard-library conversions, side by side:
converted files beside their Go source, from simple to complex.
It is readable, and it is still generated code. Do not edit a converted file by hand, because the next conversion rewrites it: change the Go, or mark a file as manually converted so the converter leaves it alone. You debug the C#, with breakpoints and stepping on the generated files. Reading and debugging the output covers this, and the Tour of go2cs shows Go and its C# side by side.
Reference it like any other library. A Go package becomes a .NET assembly: a published one is a NuGet
PackageReference, and one you convert yourself is a ProjectReference. Go's strings, slices, maps,
errors and multiple results each have a C# shape, and
Consuming converted Go from C# shows every one with working code, rough
edges included. The road runs one way: Go source cannot call a .NET API.
You can, and if you need Go's own speed it is the better choice: export the Go functions as C, build a
native library, and import it with P/Invoke. The cost is a native binary to build and ship for every
platform, a C toolchain, two runtimes and two garbage collectors in one process, and a boundary where
every string and slice is copied or pinned. Converted code is managed code in one runtime. It builds
with dotnet build, deploys as part of your application, and you can step into it in the debugger.
It is slower than native Go, and that is the trade.
Yes. go2cs -recurse=nuget converts a module and every third-party package it imports, in dependency
order, and writes a solution that restores and builds
(Converting a real-world Go module). Not every module converts cleanly yet. A
dependency that uses assembly or unsafe shortcuts may need its pure-Go build tag, and real code still
turns up converter bugs. When one dependency blocks you, -recurse=module,nuget converts your own packages
first. Third-party modules: where they trip today
is the honest list, and Validated Modules names the modules that pass their own
tests.
It runs, and it costs you. A converted program can be published with Native AOT and starts much faster than the same program under the JIT. The publish itself is slow and the executable is large, because every converted package the program references is compiled in full, and once running the program is slower than the JIT on most measurements. Known issues has the measured cost and the platform it was measured on, and the Roadmap has the work under way to reduce it.
Three kinds of NuGet package, all open source: the runtime library (go.lib),
the converted standard-library packages your code imports (go.<package>), and the source generators
(go.gen), which run only when you compile. They are built and versioned
together, so a project uses one version of all of them. A converted program
needs the .NET runtime, or you publish it self-contained. It does not need Go installed to run. You need
Go only to convert.
Not the converter's. LICENSING.md is the authority, and says, under Generated output:
Code generated by go2cs is not subject to the go2cs converter's AGPL license merely because it was produced by go2cs. Rights in generated output remain governed by the rights applicable to the input source and any separately licensed components incorporated into or referenced by the output.
src/go2cs/LICENSE-EXCEPTIONstates this as a binding additional permission.
And of the converter's own license:
The public converter grant is AGPL-3.0-only, not “or later.” The full text is in
src/go2cs/LICENSEandLICENSES/AGPL-3.0-only.txt. The copyright holders grant one additional permission under AGPL section 7: the go2cs Converter Output Exception insrc/go2cs/LICENSE-EXCEPTION, which states that the converter's output is never a covered work merely because go2cs produced it and carries the MIT grant for the embedded templates and other original scaffolding reproduced in that output.
The same page's table gives the rest: the runtime library and the source generators are MIT, and the converted standard library is BSD-3-Clause, with Go's upstream notices.
Running the converter, locally or in your own build, triggers no AGPL obligation; see the README's License section.
No. A source conversion from C# to Go would need so many restrictions on the C# that it would not be practical. To call compiled .NET code from Go instead, see go-dotnet, which hosts the .NET runtime, or embedding Mono through cgo.
The Go file is not UTF-8. It is almost always a file made in Windows PowerShell 5.1 with > or
Out-File, which write UTF-16, and then edited in place. Go source must be UTF-8, so go build fails
before go2cs is involved at all.
The walkthrough's note shows how to create the file as UTF-8 and a
one-line command that re-saves a file that is already UTF-16.