Runtime Overview
Understand the complete runtime from core native representations through collections, data, I/O, networking, concurrency, and platform services.
How to read the runtime
Sharp Runtime is easier to understand as a set of subsystem families than as a flat list of more than a thousand public headers. The lowest layer supplies native representations and contracts. Above it sit collections, text and data, I/O, networking, concurrency, and platform-facing utilities. Each family remains selectable through a physical CMake graph.
Representation map
| C# / .NET concept | Sharp Runtime / C++ representation | Important difference |
|---|---|---|
string | SharpRuntime::String = std::string; System::String static helpers | UTF-8 byte storage, mutable native value, no managed null or interning contract |
T[] | std::vector<T> plus System::Array algorithms | Vector owns and can reallocate; no CLR array base or runtime covariance |
Span<T> | Pointer and signed element length | Non-owning; source storage must outlive it |
Memory<T> | Borrowed vector plus offset and length | Does not retain a managed owner; Pin only exposes native storage |
Nullable<T> | Wrapper over std::optional<T> | Contained C++ value’s copy, move, and destruction semantics remain visible |
object | Opt-in System::Object hierarchy or an unrelated native value | No universal root, boxing header, or GC identity |
Type | Wrapper around std::type_info | Identity only; no member metadata or dependable CLR classification |
| Delegate/event | Typed C++ callables and handler collections | Capture and subscription lifetime are native and explicit |
Task | Native task/continuation objects and scheduler abstractions | No C# language async/await state machine or CLR synchronization context guarantee |
Foundation: Core.Base and narrow core components
Core.Base is the largest foundational owner. It supplies fixed-width aliases, Object, Type, numeric wrappers, exceptions, arrays and views, nullable values, delegates, environment/version helpers, and many other contracts used by higher layers. Console, Uri, and TimeZone are separate physical components so applications can avoid unrelated platform code; the compatibility target Core aggregates them for older consumers.
The core layer is intentionally heterogeneous. System::String and System::Array are static algorithm containers over standard native storage. Object is a polymorphic base only for participating hierarchies. Numeric wrappers and nullable values are ordinary value-like C++ types. This is more honest and useful than forcing every API into an artificial CLR-shaped object.
Collections and buffers
Buffers provides span-oriented and binary/text buffer contracts. The collection family is split into synchronous core collections, blocking producer/consumer support, async enumeration contracts, and object-model/observable collections. This split keeps threading and component-model dependencies out of applications that only need a list or dictionary.
Native ownership affects every collection choice. A List<Widget>-shaped container of values copies or moves widgets; a container of shared_ptr values shares identity; a container of raw pointers merely borrows. Mutation can invalidate iterators, enumerators, references, spans, and views. Concurrent containers coordinate their own structure, not the thread safety of stored objects.
Text, JSON, regular expressions, and XML
The Text component supplies builders, encodings, formatting, Base64, web encoders, and Unicode-shaped helpers around the project’s UTF-8 byte-string model. It does not turn std::string into a UTF-16 CLR string. Index units, case conversion, normalization, collation, and grapheme behavior therefore need explicit evaluation.
Text.Json wraps a vendored nlohmann JSON backend with familiar documents, nodes, readers, writers, serializers, options, and converters. It is broad enough for real native data work, but it is not reflection-driven serializer parity or a source generator. Text.RegularExpressions exposes a curated regex family over a native backend; .NET-only constructs and Unicode/culture behavior are not inferred from matching names.
Xml owns readers, writers, documents, schema, and XPath-shaped behavior over tinyxml2. Xml.Linq adds names, nodes, elements, attributes, documents, and LINQ-to-XML-shaped operations. Recent remediation corrected namespace lookup, lexical validation, embedded NUL handling, document-type parsing, and other strictness boundaries. XPath variables, custom functions, and a general extension context remain outside the supported subset.
I/O, compression, hashing, and storage
The IO component contains the abstract stream model, memory and file streams, binary and text readers/writers, file and directory helpers, metadata wrappers, random access, drives, unmanaged memory streams, and FileSystemWatcher. Capability properties and lifecycle must be consulted per stream; not every base operation is abstract or supported in the same way as .NET.
Compression and ZIP are separate owners. IO.Compression uses ZLIB privately; IO.Compression.Zip uses vendored miniz. IO.Hashing holds checksums and non-cryptographic hashes, which should never be presented as security primitives. Storage resolves application paths, while IO.IsolatedStorage builds store-relative operations and confinement checks over the filesystem. It is not an OS-enforced sandbox.
FileSystemWatcher is deliberately documented as Linux/inotify-only at this pin. The current remediation makes self-disable from a callback safe and contains handler failures, but recursive watching and live notify-filter remapping remain limited. See the dedicated watcher page rather than extrapolating from the class name.
Networking
The networking family separates base address/DNS types, sockets, HTTP messages and transport, headers, HTTP/JSON integration, MIME, network information, security-shaped contracts, and WebSockets. This keeps a consumer’s direct need visible even though CMake resolves the shared closure.
Windows and POSIX socket implementations exist; host DNS, interfaces, raw sockets, ICMP permissions, and IPv6 configuration remain environment inputs. HTTP is currently buffered plain HTTP/1.1 over TCP. WebSockets support ws://. Certificates, SslStream, HTTPS, and wss:// are not supplied merely because Net.Security contains familiar names.
Threading, tasks, channels, and timers
Threading supplies native threads, monitors, events, locks, cancellation, synchronization contexts, atomics, and thread-pool-shaped behavior. Threading.Tasks adds tasks, completion sources, continuations, schedulers, and aggregate coordination. Threading.Channels adds bounded and unbounded channel readers and writers. Timers dispatches delayed or periodic callbacks.
These facilities help preserve familiar control-flow shapes, but they cannot import C# language semantics into C++. Every asynchronous path needs an owner, cancellation strategy, exception-observation path, and shutdown protocol. Capturing a raw pointer does not retain it. A callback can race destruction or reconfiguration unless the concrete type documents serialization.
Numerics, globalization, diagnostics, runtime, and security
Numerics includes vectors, matrices, quaternion, BigInteger, Complex, Decimal, and wide numeric wrappers. Correctness remediation covers overflow, parsing, special floating-point values, rounding, and defined arithmetic, but compiler capability remains visible: native __int128 is required by some surfaces and constrains current MSVC coverage.
Globalization supplies cultures, calendars, regions, comparison options, and parsing/formatting data. It is not ICU or the full .NET data set. Diagnostics provides debug, trace, stopwatch, process, stack, and analysis-shaped APIs with platform-specific depth. Runtime holds compiler-services, interop, serialization markers, handles, and runtime helpers without implementing a CLR.
The security family offers principals, permissions, authentication-shaped contracts, hashes, HMAC, PBKDF2, cryptographic operations, and platform secure random. It does not amount to a complete encryption/certificate/TLS platform. Security promises are made per algorithm and transport, not per namespace.
Component graph and external attachment
At the pinned SHA the runtime has 41 physical components and 92 direct production edges. Header-only components can only have public dependencies; compiled components may hide implementation dependencies privately. Tests have their own edges and cannot expand the production surface. ZLIB, miniz, tinyxml2, nlohmann JSON, platform socket libraries, BCrypt, and Android SDL3 are attached by their owning component rather than globally.
Use the component catalogue to select a target, the API inventory to locate public entries, and the conceptual pages to understand semantics. Those layers are complementary: a generated header list alone cannot explain ownership or a Unicode reduction, while prose alone should not hand-maintain 1,036 public header names.
Verification snapshot
The selected source registers 37 physical component test executables and one integration executable. The complete measured gate at that same SHA discovered and ran 17,131 GoogleTest cases: 17,123 passed, two skipped, and six failed. Five failures expose a Ping/raw-ICMP fallback gap under the host’s ping-group policy; one depends on missing IPv6 host state. Component graph, selective consumer, negative boundary, catalogue, and documentation checks provide evidence that a large pass count cannot provide by itself.