Objects and companions
A Kotlin object becomes a C# static class: no instance, no constructor, its members reached directly through the type. A companion object's members land as static members directly on the enclosing C# class, not on a separate Companion type. A data object nested inside a sealed class becomes a sealed subclass instead; see Interfaces, abstract and sealed classes. An object can also own a nested type the same way a class can; see Nested types.
For this declaration in CatRegistry.kt:
Call it from C# through the type; there is nothing to construct:
Object methods are PascalCased and their returns marshalled exactly like class methods; see Classes and objects.
A suspend function on an object binds as a static Task method with a CancellationToken: await Siesta.MinutesForAsync("Oreo"). See Coroutines and Flow.
Object properties
An object's own val/var properties bind as static properties on its static class, at the same type coverage a companion property already has: nullable primitives, enums, collections, and handle-typed properties.
A const val on an object or companion follows the same evaluated-constant rule as a top-level one (see Top-level declarations): an expression over another const, even one declared on a different owner, renders its evaluated value, not its source text:
A val renders get-only, a var renders get/set. A member the object only inherits — a base class property or method it does not redeclare — is flattened directly onto the static class, methods included: a C# static class cannot extend or implement anything, so an inherited member has no other place to live. The relation itself is gone: TreatPantry cannot be used as a Stockroom or an ILabelled, only through its own flattened members, and a SKIPPED_UNEXPORTED_SUPERTYPE warning names each dropped supertype at build time (this fires for every declared supertype, whether or not it is itself exported, because the C# shape has no base list to put it in).
Declaring a property and a function that render the same C# name on one object — val count beside fun count(), or an inherited method colliding with a declared property — fails the build with ERROR_CSHARP_NAME_COLLISION (CS0102), naming both Kotlin declarations; rename one of them. This is the same shared guard as an ordinary class's (see Classes and objects), which also covers a companion member colliding with an instance member on the enclosing class, and, wherever a real base class exists, a declared member that hides an inherited one of the other kind instead of colliding with it directly.
An Int?-style nullable property round-trips its null branch the same way a class property does. A lateinit var read before it is assigned surfaces in C# as a KotlinException, not a crash. A lambda-typed object or companion property binds as a static delegate property, with a setter for a var (see Lambdas and callbacks).
A Flow, StateFlow or SharedFlow object property (and a Mutable* one) binds as a static KotlinFlow<T> or its variant, read fresh on every access:
A Flow-returning object function binds the same way. See Coroutines and Flow.
Companion objects
A companion's members are static members on the enclosing class itself:
There is no separate Cat.Companion class in the generated output.
This applies to the companion of an ordinary class or an enum. The companion of an interface, a value class, or a sealed class or arm binds nothing: each of its members is skipped with a named warning, so move it to a top-level declaration or an object.
A suspend member of a companion binds the same way, as a static Task method on the owning class: await Swing.HangAsync("Oreo"). A named companion binds too. See Coroutines and Flow.
A companion Flow-returning function or flow property binds as a static member too, named or default: Cuckoo.Calls() for companion object { fun calls(): Flow<String> }, and Hourglass.Level for a StateFlow in companion object Sand. See Coroutines and Flow.
A member extension declared inside an object or a companion (val Loafer.snooze, suspend fun Loafer.curlUp(minutes: Int)) binds as a static method that takes the receiver first, for example Napkin.GetSnooze(loafer) and await Napkin.CurlUpAsync(loafer, 5). See Member extensions.
Method overloads
Two or more same-named members on an object or a companion object generate one natural C# overload set, resolved by parameter type like any other C# overload, including an Int overload beside an enum overload:
See Method overloads in Classes and objects for the same rule on class methods, top-level functions, and extension functions.
Method default parameters
A defaulted parameter on an object or companion member widens to its nullable C# form, using the Kotlin default when the caller passes null:
A defaulted parameter followed by a non-defaulted one stays required-but-nullable instead of optional, so pass it explicitly (null for it still means "use the Kotlin default"). A defaulted parameter the bridge cannot route to any non-null C# form is dropped from the trailing signature entirely.
The events parameter does not exist in C#. See Constructor and method default parameters for the full rule.