Known Limitations
Platform gaps, missing features, stub-only classes, and known differences from .NET.
No Garbage Collector
sharp-runtime has no garbage collector. System::GC is a stub that does nothing.
All memory management is explicit C++ RAII. This is intentional — GC adds complexity and latency
that is unacceptable in game runtime code (the primary use case via CNA).
Impact: Circular reference cycles with shared_ptr cause memory leaks.
Code that assumes GC will clean up must be refactored to use RAII patterns.
POSIX-only Subsystems
The following subsystems work on Linux, macOS, and Android (via NDK) only:
| Subsystem | Reason | Windows/Emscripten status |
|---|---|---|
System::Net::Sockets | Uses POSIX socket APIs | Not implemented |
System::IO::RandomAccess | Uses pread/pwrite | Has Win32 fallback (needs verification) |
System::AppDomain | Uses POSIX process/env APIs | Not fully implemented |
System::AppContext | Uses POSIX paths | Not fully implemented |
System::TimeZoneInfo | Uses localtime_r, /usr/share/zoneinfo | Not portable |
No Reflection
System::Type is a stub. There is no runtime type metadata, no dynamic method invocation,
no Activator.CreateInstance, and no attribute inspection at runtime.
Only GetTypeName() (returns a string) is available for type identification.
See Reflection.
Stub-only Classes
These classes exist as headers for API compatibility but have minimal or no implementation:
| Class | Notes |
|---|---|
System::GC | No garbage collection; all methods are no-ops |
System::Type | No runtime type metadata |
System::Activator | CreateInstance not implementable without reflection |
System::Threading::SynchronizationContext | Stub; Progress<T> calls handlers synchronously |
System::Diagnostics::StackTrace | No stack capture |
System::Diagnostics::StackFrame | No frame info |
| Attribute classes (all) | Exist for syntax, no runtime effect |
HttpClient — No TLS / HTTPS
System::Net::Http::HttpClient is implemented but supports plain HTTP only.
HTTPS (TLS/SSL) is not implemented. Do not use for production HTTPS requests.
A future improvement would require linking an SSL library (e.g., OpenSSL or mbedTLS) which has not been approved as a dependency yet.
Regex Limitations
System::Text::RegularExpressions::Regex uses std::regex as its backend.
Known limitations compared to .NET Regex:
- No named capture groups (
(?<name>...)) - No lookbehind assertions
std::regexcan be significantly slower than .NET's regex engine for complex patterns
No LINQ
There is no LINQ implementation. C# code using .Where(), .Select(),
.GroupBy(), etc. must be rewritten as explicit loops or use C++ standard algorithm
functions (std::find_if, std::transform, etc.).
No C# async/await Syntax
C# async/await coroutines have no direct language equivalent in C++. Task and ValueTask APIs are provided by the SharpRuntime::Threading.Tasks component, but they do not reproduce the full C# awaitable pattern. Ported asynchronous code may need threads, callbacks, or a C++-native asynchronous design.
SynchronizationContext
System::Threading::SynchronizationContext is a stub.
Progress<T> calls its handlers synchronously rather than marshalling them to a context.
For single-threaded game use (the primary use case) this is the correct behavior.
AppDomain — Linux-only getBaseDirectory
AppDomain::getBaseDirectoryProperty() reads /proc/self/exe to determine
the executable path. This works on Linux but not on macOS (which uses _NSGetExecutablePath)
or Windows. The method may return an incorrect or empty path on non-Linux platforms.
Additionally, extern char** environ in Environment.cpp must remain at
file scope (not inside namespace System) — moving it causes a PIE relocation error.
String Encoding Differences
- C#
stringis UTF-16; sharp-runtimestd::stringis UTF-8 by convention - C#
charis 16-bit;charcs=char16_tin sharp-runtime - String
Lengthin .NET = UTF-16 code units;size()in C++ = bytes - Multi-byte UTF-8 characters will have
size()> character count
No String Null
In C#, a string variable can be null. In sharp-runtime,
std::string cannot be null — the convention is to use empty string ("")
where C# would use null.
Array Fixed Size
C# arrays are fixed-size after creation. std::vector<T> is dynamic.
While this is more flexible, code that relies on array length staying constant must be careful
not to accidentally resize the vector.
No Checked Arithmetic
C# has checked / unchecked contexts for integer overflow detection.
C++ has no equivalent. Integer overflow is undefined behavior for signed types in C++ —
use OverflowException manually if overflow detection is needed.
Thread Safety
Thread safety of individual classes is not guaranteed unless explicitly documented.
The standard collections (List<T>, Dictionary<K,V>, etc.)
are not thread-safe for concurrent writes — use System::Collections::Concurrent
types or external synchronization.
WeakReference Generic Form
WeakReferenceT<T> is the generic form (not WeakReference<T>)
because C++ cannot have a class template and a plain class with the same name in the same namespace.
Replace WeakReference<T> with WeakReferenceT<T> when porting.
Emscripten Build
Emscripten (WebAssembly) compilation has never been CI-tested in this repository. Platform guards exist but are not validated. POSIX-only subsystems would fail to link.