Supported features
A scannable index of what maps to what, and in which direction. Look here to find out whether a Kotlin or C# shape crosses the bridge at all, and what it becomes on the other side.
This page carries neither the how nor the why. How to use a mapping lives in the topic page linked in the Docs column; why it maps that way lives in the architecture decision records.
Glyph | Meaning |
|---|---|
| Kotlin → C#: a Kotlin feature you author, surfaced as C# (forward, code generation) |
| C# → Kotlin: a feature from a consumed C# NuGet package, surfaced as Kotlin (reverse) |
| both directions |
| Kotlin ⇸ C#: a Kotlin feature with no C# projection; the row says why and what the processor does with it |
⇄ is the target state. Where a row is one way, the Notes say whether the gap is fundamental (the reverse direction reads a compiled assembly you do not own, so some source-only Kotlin concepts cannot round-trip) or simply not built yet: see ROADMAP.md.
Primitives
Primitive types follow the standard Kotlin/Native C interop mappings.
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
| ⇄ |
| ||
| ⇄ |
| ||
| ⇄ |
| ||
| ⇄ |
| ||
| → |
| A UTF-16 code unit, at a property, parameter, method return and | |
| ⇄ |
| UTF-8 marshalling. | |
| → |
| Property getters use a two-call has-value pair; top-level, method and extension returns use one call. | |
| ⇄ |
| → single call, | |
exported class type, nullable ( | → |
|
| |
| → |
| Property, parameter, return. Kotlin to C# truncates below 100ns and throws outside years 0001-9999. Also a collection component and a | |
| → |
| Crosses as RFC 9562 text on the | |
| → |
| Ticks. Kotlin to C# truncates below 100ns and throws for infinite or out-of-range values; C# to Kotlin is exact within ±146y. Also a collection component and a | |
| → |
| Copied on every crossing, never a view. Binds at a property, parameter, return, | |
| → |
| At every position, the runtime C# value (boxed primitive, wrapper you dispose, struct, collection); |
OOP constructs
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
| ⇄ |
| → | |
wrapper dropped without | → | released when the .NET GC finalizes it | Eventually, on the finalizer thread, never at process exit; | |
dependency-module type (cross-module export) | → | same class, generated into this module's package | A type your API exposes but a dependency declares is admitted by | |
constructor | ⇄ |
| → defaults widen to one nullable signature, | |
| → |
|
| |
| ⇄ |
| → | |
| → |
| Subclasses inherit the handle; an unimplemented member renders | |
| → |
| Arms are nested/sibling classes via | |
| → |
| Binds at every sealed position; a returned value is the concrete arm. A superclass on one arm flips | |
| ⇄ |
| → singleton; methods and its own | |
| → | sealed subclass | Binds | |
| ⇄ |
| → extension methods; companion members are statics on | |
| ← |
| Reverse only: the value decomposes onto the wire, so there is no handle and no | |
companion object | → | static members | ||
| ⇸ | Fundamental: there is no C# projection of a Kotlin annotation. A public one skips once, named, and using it on an exported declaration changes nothing. | ||
| ⇸ | No eager-copy story exists for a lazy sequence, so a parameter, return or property carrying one skips, named, and the C# declaration that lost it says so in | ||
declaration marked with an author's | ⇸ | A marked type is never declared; a marked member skips while its owner still exports. | ||
| → | ordinary declaration | The |
Properties and top-level declarations
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
member property (get/set) | ⇄ | property (get/set) | → nullable and handle-typed properties; an inherited unimplemented member renders | |
| → | member named | Sets one | |
instance method return (object, | → | matching C# return type | Same plan cascade as a property getter, except a nullable numeric return uses a single call: a method may have side effects and cannot be invoked twice. | |
top-level function | → |
| One static class per source file. A file whose every declaration skips emits no class at all, and a name colliding with a same-file top-level property fails generation. | |
top-level property | → | static property | get and set, including nullable. | |
| → |
| Value is the compiler's evaluated constant, so an expression or a dependency const binds; hex/underscore literal spelling isn't kept. | |
extension function | → | static method | A real C# extension method on every receiver a parameter binds as, generic and bare | |
extension property | → | C# 14 | Same receivers as a function, generic ones as | |
bare | → |
| Homes on the first bound's | |
star-projected extension receiver ( | → |
| A synthesized type parameter named after the class; a projection stays refused at every other position. | |
member extension ( | → | instance method | The receiver is the first parameter, named | |
member extension property ( | → | accessors | The receiver is the first parameter; a | |
member extension in an | → | static, | Property or function, |
Generics
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
| ⇄ |
| → type-erased wrapper; a bare | |
a closed | → |
| A returned wrapper is yours to dispose, a passed one is borrowed; a | |
a generic interface at any position ( | → |
| A Kotlin value is the wrapper | |
generic | → |
| An arm fixing the argument ( | |
| ⇄ | typed constructors | → typed, | |
a method declared on a | → | instance method on the generic carrier | Every | |
a property declared on a | → | its own C# type |
| |
a type nested in a | → |
| Never | |
top-level | → | static generic method | Every | |
| → |
|
| |
| → | static or extension | Each call runs on its own scope, so only the token cancels it; a companion and an instance | |
| → |
| The class is | |
| → |
| The class is | |
| → |
|
| |
| → |
|
| |
| → | generic method |
| |
a C#-implemented interface at an erased generic position (lambda, | ⇄ | the interface itself, not its backing wrapper | → returns the same instance · ← a Kotlin-backed value at | |
| → |
|
| |
| → |
| ||
| → | the underlying type | Use-site |
Collections
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
| → |
| Eager copy at a property (settable when every component is wrappable), a return and a parameter; | |
| → |
| Eager copy; a parameter never writes back to Kotlin. Settable as a property when every component is wrappable; | |
| → |
| Eager copy at a property, return and parameter; a key or value may be a scalar, enum, handle, interface or collection. A nullable key ( | |
| → |
| Eager copy; a parameter never writes back. Settable as a property when every component is wrappable; | |
| → |
| Eager copy at a property, return and parameter, over the same component set as | |
| → |
| Eager copy; a parameter never writes back. Settable as a property when every component is wrappable; | |
| → |
|
| |
| ← |
| Reverse only: an eager copy, so every C# shape binds read-only at every position. A mutable Kotlin type would let an |
Functions and lambdas
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
| ⇄ |
| Every owner, nullable and | |
function returning a lambda | ⇄ |
| → every owner, | |
| → |
| Per-call, arity 0-3; payload and result take | |
stored callback parameter | → |
| Subscribe and dispose; | |
Kotlin lambda at a bound delegate parameter | ← |
| A bound method or constructor's delegate parameter takes a plain Kotlin lambda, | |
interface parameter (C# → Kotlin) | → | C# implements |
| |
a bound C# interface in a lambda payload or result | ⇄ | the interface itself, | The lambda receives the object you implemented, and a result you return is the one Kotlin reads; plain, | |
| → | regular method | ||
| → | generic method | Binds at top level, reified at its bound; on a member or with | |
value class ( | → | underlying type / record struct | A | |
value class at an ordinary position | → | the same record struct | Over any bound underlying ( | |
value class as a | → | the same record struct, in | Element, map key or map value, over any bound underlying; | |
generic value class ( | → |
| Binds at every position, over a | |
same-name function overloads | ⇄ | method overload set | → one natural C# overload set per container, the numbering hidden on the export symbol; a pair differing only in reference nullability fails generation · ← each member keeps its Kotlin name | |
function/method default parameters | → | one widened signature | Any subset settable by name; already-nullable params use shared |
Exception handling
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
thrown exception | ⇄ |
| → shared identity; mapped types keep BCL bases · ← throws surface as | |
stack trace | → |
| Kotlin frames only, host frames trimmed; a cause arrives only as | |
| → |
| The cause chain is preserved. | |
| → |
| Subclasses map too; | |
| → |
| Out: an unthrown exception, a snapshot per read. In: any exception arrives as a | |
| → |
|
| |
| → |
| On every | |
property getter / setter throws | → | propagated | ||
constructor / | → | propagated | Primary, secondary, a data class |
Async and coroutines
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
| → |
| Two | |
| → |
| A nullable string, object or primitive return carries its | |
| → | the same mapped C# type | Admits like any other position; out-of-scope skips named via | |
| → | record struct / enum, unboxed or cast on completion | Null-guarded when nullable. A generic value class ( | |
| ⇄ |
| → completes with the interface itself, nullable included · ← a value stored through a C# implementation comes back as the caller's own instance, not a fresh wrapper | |
| ⇄ |
| The same shape as a | |
| → |
| Arity 0-3, constructors included; payloads as a lambda parameter. Kotlin owns the delegate until a GC round. A nullable lambda binds as | |
plain | → |
| Every owner; kept alive until the | |
| → |
| Primitive, | |
structured concurrency | → | honoured | ||
coroutine cancellation | → |
| Suspend lambdas included. | |
in-flight async drain | → |
| Graceful drain, owned by the first class in the chain, sealed base, or reachable interface that declares a | |
| → |
| Cold streams at a method or property return; a | |
| → | static | Each enumeration runs on its own scope; a cold flow needs no | |
member types of an interface a C# class implements | → | the member as | Classes, collections, value classes, nullables, | |
| → |
| Kotlin awaits and collects them; cancellation reaches your token. | |
| → |
| A null emission is a genuine item, not the end of the stream, for an interface, | |
| → |
|
| |
| ⇄ |
| → the element is spelled with the interface itself, nullable included · ← a value stored through a C# implementation comes back as the caller's own instance | |
| → |
| Hot, always current. A declared | |
| → |
| A nullable element and a nullable member, independently or combined. | |
| → |
| Opt-in; | |
| → |
|
| |
| → |
|
| |
| → |
| Stays a | |
| → |
| Await acquisition once; dispose the acquired holder separately from its owner. | |
| → |
|
| |
| → | the collection type, never |
| |
| → |
| Spelled and read as the property route spells the same type; | |
A class, | → | the mapped C# type, spelled exactly as the return position on the same member, passed as | Nullable binds as | |
An enum parameter on a | → | the mapped C# enum type | Bound by ordinal: | |
| → |
| Nullable too. A | |
| → |
| The receiver is a leading parameter on its own wire, nullable too; the same types bind as a | |
| → |
| Writes cross as ticks or text, or through the value class box pair. An awaited | |
A nullable primitive/ | → |
| ||
A default argument on a scalar/ | → | one widened signature, or required-but-nullable | A non-null collection default stays required, a nullable one widens to | |
| → |
| Spelled and read as every other route spells the same Kotlin type. A sealed-base component binds on | |
| ← |
| A faulted task is a catchable | |
| ← |
| Pull-based and cold: the C# method runs at |
Documentation comments
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
KDoc ( | → |
| Every generated declaration mirroring a documented one carries it. The first paragraph is the summary, the rest the remarks; |
Runtime and packaging
Kotlin | ⇄ | C# | Notes | Docs |
|---|---|---|---|---|
the fixed | → | the same | Ships once as a versioned | |
Two Kotlin-built NuGet packages in one .NET project | → | package-local generated APIs and native runtimes | Share exception and | |
the consumer's Kotlin version | ⇸ | no C# projection | Any Kotlin from 2.4.0 up works; below it the build fails at configuration time, above the last tested version it warns. | |
| → | the package layout | One floor | |
every forward | → | the matching | Always the library, then the package relative to | |
every declaration generated by | ← | the bound C# package's API | Marked |