Standard-library API catalogue
Use this catalogue to distinguish callable CLR declarations, established source forms and implementation details. The public namespace root is DirectSharp. The library is planned primarily in C#; there is no installable implementation yet. Behavior and examples explain each family, and the implementation plan records its C# strategy.
A method name in a source example does not by itself select every overload or export container. The declarations below are the selected CLR contracts. The later tables preserve established type/behavior requirements without guessing missing public declarations.
Contract map
| Family | Callable contract | Ownership and execution | Declaration boundary |
|---|---|---|---|
| Gate | Four acquisition overloads returning IDisposable permits | Caller owns Gate; each successful acquisition owns one release | Permit concrete type and helper ABI are private |
| Consumable acquisition | IConsumable/ConsumeResult and IConcurrentConsumable | Borrow source; acquisition reports item versus permanent completion | Consumables factories and ILiveConsumable producer members are declared below |
| Strict selection | Take(count), Take(start, end), Skip(count), TakeLast(count) | Deferred enumerable; source-reading and cleanup failures propagate | DirectSharp.Collections.SequenceExtensions; explicit opt-in; Integer counts/positions |
| Try selection | TryTake count/interval, TrySkip, TryTakeLast return nullable IReadOnlyList | Collect at call; no source restart; absent when no selection | Concrete collected container is an implementation detail |
| Text and Unicode | Named values and five typed conversion/traversal helpers | Scalar traversal is deferred; construction validates before narrowing | Static Chars/Unicode; fixed const fields and platform NewLine getter |
| Text transformations | Fifteen String extension members, including layout and context-specific encoders | Selected null/Unicode/validation profiles; Integer layout inputs | Opt-in DirectSharp.Text.TextExtensions |
| Numeric/format helpers | Twelve selected Decimal/Double Round/Truncate/Floor/Ceiling members and recorded formatting forms | AwayFromZero helper default; native typed Math behavior | Root DirectSharp.Numbers; bare source-call binding remains separate |
| Services | Six keyed/unkeyed lookup members; missing-service exception identity | Resolve within provider/scope; retrieved values stay borrowed | Two identity-bearing constructors; native bridge declarations remain backend-specific |
| Features and wrappers | Typed compile-time declarations and source expansion | Discovered from source/references; no runtime feature object | Metadata wire format and engine host ABI are compiler/tooling details |
Gate permits
These are member fragments of DirectSharp.Gate, with ordinary System, System.Threading and System.Threading.Tasks imports. They describe signatures, not a buildable class implementation:
public IDisposable Acquire(CancellationToken cancellation = default);
public IDisposable Acquire(TimeSpan timeout, CancellationToken cancellation = default);
public ValueTask<IDisposable> AcquireAsync(CancellationToken cancellation = default);
public ValueTask<IDisposable> AcquireAsync(TimeSpan timeout, CancellationToken cancellation = default);
| Source construction | Established meaning |
|---|---|
| new Gate() | One permit |
| new Gate(count) | Positive permit count |
| new Gate(count, timeout) | Permit count and default acquisition timeout |
The no-timeout acquisition overload uses the configured default; explicit TimeSpan overrides it. A permit releases at most once and never owns the Gate. There is no unpaired public Release or exposed native semaphore. Timeout, caller cancellation and grant compete under the Gate arbitration contract, not a new post-grant check.
A failed acquisition runs no body and supplies no permit. The owner disposes Gate after all holders/waiters finish. Disposal while pending/held throws InvalidOperationException and leaves it usable; successful disposal is idempotent. Private permit classes, semaphore selection and timer machinery are implementation decisions behind the selected IDisposable result.
Consumable acquisition
This contract uses ordinary System, System.Threading and System.Threading.Tasks names. The result representation illustrates the selected payload/completion distinction; its fields are not an adapter implementation:
namespace DirectSharp;
public interface IConsumable<T>
{
ValueTask<ConsumeResult<T>> AcquireAsync(CancellationToken cancellation = default);
}
public interface IConcurrentConsumable<T> : IConsumable<T>
{
}
public readonly struct ConsumeResult<T>
{
private readonly T item;
public bool HasItem { get; }
public T Item => HasItem ? item
: throw new InvalidOperationException("No item after completion.");
private ConsumeResult(T item) { this.item = item; HasItem = true; }
public static ConsumeResult<T> FromItem(T item) => new(item);
public static ConsumeResult<T> Completed => default;
}
| Acquisition result | Interpretation |
|---|---|
| FromItem(null), when T permits it | A real item; HasItem is true |
| FromItem(0) or FromItem(false) | A real item |
| Completed / default result | Permanent completion; Item access throws InvalidOperationException |
| Source is open but temporarily empty | Wait; do not fabricate Completed |
| Cancelled native wait or failed source read | Exception; not a completed result |
Await each acquisition operation according to its ValueTask contract. The interface itself promises no overlapping-acquisition safety. IConcurrentConsumable adds that capability and item validity across later acquisitions; it does not make mutable payloads thread-safe. A raw database reader still cannot feed concurrent bodies directly.
Native source sessions
The following describes adapters' required behavior, not proposed factory names. A consume loop over a compiler-known native source does not require a feature activation block.
| Native source | Item and terminal boundary | Required implementation account |
|---|---|---|
| Queue / Stack | Dequeue FIFO / pop LIFO; first empty observation ends that drain session | Borrow collection; no new thread-safety promise; a later session is separate |
| ConcurrentQueue / ConcurrentStack / ConcurrentBag | Native order; explicit producer completion plus drain | Coordinate producer admission, arrival notification and terminal state through a completion-aware wrapper |
| BlockingCollection | Native take order; completed adding and drained | A native blocking wait must remain owned/joined if bridged asynchronously |
| ChannelReader | Native read order; writer completed and drained | Wait through temporary emptiness, retry competing read misses, preserve native fault/cancellation behavior |
| IDataReader / DbDataReader | Current IDataRecord; Read/ReadAsync false for current result set | Do not call NextResult or dispose caller's reader; raw row views remain ephemeral |
| Explicit text-line adapter | String line; native EOF terminates | Preserve blank lines; borrow reader and its encoding/newline policy; serialize shared-cursor acquisition |
| Explicit byte-chunk adapter | Independent Byte[]; zero-byte positive-size read terminates | Positive chunk size; retain short positive reads; no seek/Length requirement or guessed text encoding |
A completion-aware live collection wrapper must observe coordinated producer operations. Arbitrary direct writes to the underlying concurrent collection cannot be assumed to wake its waiters. Explicit producer failure closes admission, drains already-buffered items in native order, then retains/rethrows that original failure. Cancelling a consumer wait and failing a consumer body do not report producer completion or add retry/requeue. Native channels retain their own behavior rather than inheriting this wrapper's terminal-state implementation.
Sources and acquired application objects remain borrowed. An adapter has no implicit permission to dispose them. See reader and stream lifetimes. Factories and terminal-reporting members are specified below; private native adapter registration remains compiler integration work.
Explicit borrowed-source factories
DirectSharp.Consumables is a static class. These ordinary CLR factory fragments use System.Collections.Generic, System.Collections.Concurrent, System.Data, System.Data.Common, System.IO and System.Threading.Channels types:
public static IConsumable<T> FromQueue<T>(Queue<T> source);
public static IConsumable<T> FromStack<T>(Stack<T> source);
public static IConcurrentConsumable<T> FromBlockingCollection<T>(BlockingCollection<T> source);
public static IConcurrentConsumable<T> FromChannel<T>(ChannelReader<T> source);
public static IConsumable<IDataRecord> FromReader(IDataReader source);
public static IConsumable<IDataRecord> FromReader(DbDataReader source);
public static IConsumable<string> ReadLines(TextReader source);
public static IConsumable<byte[]> ReadChunks(Stream source, int chunkSize);
A factory rejects a null source with ArgumentNullException before doing any source work. ReadChunks then rejects nonpositive chunkSize with ArgumentOutOfRangeException. Creation performs no read, enumeration or disposal. Sources remain borrowed; there is no leaveOpen/ownership parameter.
Each adapter is one acquisition session. Create a new reader session after explicitly advancing to another result set. Use one session per shared cursor and obey the native source's concurrency constraints. Marker-returning adapters support overlapping acquisitions and stable item lifetime, serializing native access internally when required, including a single-reader channel. That protection does not coordinate unrelated native reads or independently created adapters. The other return types do not advertise a new concurrent capability; raw database-reader concurrent consumption stays invalid.
Known native consume sources remain directly usable without a factory call. Explicit line and chunk modes make their interpretation clear. Adapter concrete types and registration metadata are private.
Live concurrent collection producers
DirectSharp.ILiveConsumable is an ordinary interface, adding producer members to the concurrent consumer contract:
public interface ILiveConsumable<T> : IConcurrentConsumable<T>
{
void Add(T item);
bool TryComplete();
bool TryComplete(Exception failure);
}
The static Consumables factories are:
public static ILiveConsumable<T> FromConcurrentQueue<T>(ConcurrentQueue<T> source);
public static ILiveConsumable<T> FromConcurrentStack<T>(ConcurrentStack<T> source);
public static ILiveConsumable<T> FromConcurrentBag<T>(ConcurrentBag<T> source);
Factories reject null without acquiring items. One wrapper coordinates a collection's active producer session. Add coordinates admission, insertion and arrival notification; producers must not bypass it with outside writes that race this protocol. Pass IConcurrentConsumable to workers when they should receive only the acquisition contract.
The first terminal transition wins atomically. TryComplete returns true only when that call closes admission. Later terminal calls return false and preserve the first outcome. The failure overload rejects null with ArgumentNullException before attempting transition; the no-argument form means successful producer completion. Add before terminal closure contributes a buffered item; Add after closure throws InvalidOperationException and admits nothing.
Both routes drain buffered items in native order. Success then reports Completed; failure then retains/rethrows the original exception. Consumer cancellation or body failure does not close producers. No acknowledgement, requeue, automatic retry, bounded capacity or item-disposal ownership is added.
This complete action illustrates a finite producer session before bounded consumption. It uses the consumable library contracts:
public action PrintPendingCustomers()
let native = new Global.System.Collections.Concurrent.ConcurrentQueue <of String>()
let jobs = Consumables.FromConcurrentQueue(native)
jobs.Add("customer-101")
jobs.Add("customer-102")
jobs.TryComplete()
concurrent consume customerId from jobs with limit: 2
Global.System.Console.WriteLine(customerId)
end consume
end action
The native queue stays caller-owned and can be used after the session has settled. Normal mutable payload coordination is still the application's job.
Sequence exports and imports
The static class DirectSharp.Collections.SequenceExtensions declares these ordinary extensions, using System.Collections.Generic. Counts and inclusive positions are Integer/System.Int32; no additional Long overload is selected:
public static IEnumerable<T> Take<T>(this IEnumerable<T> source, int count);
public static IEnumerable<T> Take<T>(this IEnumerable<T> source, int start, int end);
public static IEnumerable<T> Skip<T>(this IEnumerable<T> source, int count);
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count);
public static IReadOnlyList<T>? TryTake<T>(this IEnumerable<T>? source, int count);
public static IReadOnlyList<T>? TryTake<T>(this IEnumerable<T>? source, int start, int end);
public static IReadOnlyList<T>? TrySkip<T>(this IEnumerable<T>? source, int count);
public static IReadOnlyList<T>? TryTakeLast<T>(this IEnumerable<T>? source, int count);
The DirectSharp root auto-import does not import this child namespace. To use these extensions in DirectSharp, add the following to the relevant file or existing project block:
import Global.DirectSharp.Collections
Existing System.Linq.Enumerable calls retain their semantics. If both extension families are equally applicable, ordinary overload binding diagnoses ambiguity; neither receives hidden priority. Qualify DirectSharp.Collections.SequenceExtensions or System.Linq.Enumerable to choose deliberately. This is an ordinary namespace/member choice, not a new language rule.
For example, this action fragment assumes items contains integers 0 through 6 and both namespace families are available. Each invocation selects its static declaration explicitly:
let strict = Global.DirectSharp.Collections.SequenceExtensions.Take(items, 10)
let clipped = Global.System.Linq.Enumerable.Take(items, 10)
Both are deferred. Full strict traversal exposes the available prefix then fails on shortage; the LINQ sequence clips to the available seven items. No package is installed or namespace imported merely by writing a qualified name.
Sequence result and timing types
The source forms below are DirectSharp helper contracts. Imported LINQ keeps its own behavior. The table does not introduce new extension-method priority over an existing .NET member.
| Source form | Established result | Work and failure boundary |
|---|---|---|
| items.First / items.Last | Selected item, or actual nothing when empty | Ordinary source evaluation; do not substitute a numeric/default item for absence |
| items.Take(count) | Deferred IEnumerable of source items | Reject invalid count immediately; shortage may fail after a yielded prefix |
| items.Take(start, end) | Deferred IEnumerable; both positions inclusive | Reject invalid bounds before enumeration; require complete interval when traversed |
| items.Skip(count) | Deferred IEnumerable remainder | Require count items to skip; exact-length skip is present empty |
| items.TakeLast(count) | Deferred IEnumerable tail | General source must reach exhaustion; bounded tail storage, no Count prepass |
| items.TryTake(count) / items.TryTake(start, end) | Nullable IReadOnlyList of selected items | Collect bounded selection at call; normalize negative positions/counts and clip availability |
| items.TrySkip(count) | Nullable IReadOnlyList remainder | Collect remainder at call; exhaustion/storage cost is part of this contract |
| items.TryTakeLast(count) | Nullable IReadOnlyList tail | Reach exhaustion at call for a general enumerable; keep only needed tail |
Strict zero Take/TakeLast is a present empty sequence; Skip(0) yields the source. Try returns nothing when no items are selected. A missing source throws ArgumentNullException in strict helpers before bounds validation; Try helpers return nothing before normalization without enumeration. Reading/cleanup failures propagate instead of returning a successful partial selection.
Collected membership/order is reused without rereading the source; referenced payloads are not deep-copied. Suitable already-available Count/Length and indexing can optimize equivalent observations. A separate enumerating Count pass or silent materialization of a strict helper is not allowed. The full sequence rules include prefix, empty, negative, reversed and source-failure cases.
The First/Last source accessor forms are established separately from a universal CLR generic optional-result signature. Do not guess a new optional runtime type, silently substitute default(T), or claim that C# unconstrained T? always means Nullable<T>. Their exact exported/binding representation belongs with the remaining helper catalogue. Ordinary property-read absence already follows the read-chain rules; an unselected CLR helper's null/async-source contract is a separate API question. The C# absence strategies show typed nullable projection and private presence/payload handling without selecting a new public export.
Text member types
DirectSharp.Chars and DirectSharp.Unicode are root-level static classes. Fixed named values are public const fields; Chars.NewLine is a public static String getter returning Environment.NewLine. The five static conversion/traversal declarations are:
// DirectSharp.Chars
public static char FromCodeUnit(long value);
public static int CodeUnit(char value);
// DirectSharp.Unicode
public static string FromCodePoint(long value);
public static int CodePoint(string value);
public static IEnumerable<int> CodePoints(string text);
The values and execution rules remain: CLR aliases char, string, long and int correspond to Char, String, Long and Integer.
| Member | Input and result | Validation/timing |
|---|---|---|
| Chars.FromCodeUnit(value) | Long to Char | Validate 0–65535 before narrowing; surrogate units are allowed |
| Chars.CodeUnit(value) | Char to Integer | Return its UTF-16 unit, including an isolated surrogate |
| Unicode.FromCodePoint(value) | Long to String | Valid scalar 0–0x10FFFF excluding surrogate values; reject invalid input |
| Unicode.CodePoint(value) | String to Integer | Exactly one valid scalar; missing input throws ArgumentNullException, other invalid input ArgumentException |
| Unicode.CodePoints(text) | String to deferred IEnumerable of Integer | Null check at call; fresh strict UTF-16 traversal per enumeration; malformed suffix fails when reached |
Out-of-range scalar/unit construction throws ArgumentOutOfRangeException. Validation occurs on the Long value before any narrowing. A supplementary scalar produces a surrogate pair String; a grapheme can contain several scalars. CodePoints does not replace malformed units or decode an unvisited suffix after early exit.
| Named-value group | Members | Type/value rule |
|---|---|---|
| Fixed Chars | CR, LF, Tab, Null, Escape, Backspace, FormFeed, VerticalTab, Space, SingleQuote, DoubleQuote, Backslash | Char, including U+0000 for Null |
| Chars.CRLF | Carriage return followed by line feed | String |
| Chars.NewLine | Runtime platform newline | String; not one universal newline literal |
| Unicode named values | NBSP, ZeroWidthSpace, BOM, Bullet, Ellipsis, LineSeparator, ParagraphSeparator, ReplacementCharacter | String containing the named scalar |
The value tables give every selected scalar/unit. Fixed fields are usable in ordinary CLR constant contexts and follow normal constant inlining. Platform NewLine is a runtime property, not a universal portable constant. Additional text/numeric overloads must preserve the selected values, types and timing.
Other recorded text forms
These ordinary composable transformations are the fifteen selected extension members of the public static class DirectSharp.Text.TextExtensions. They are library operations, not extra language statements:
public static string Upper(this string source);
public static string Lower(this string source);
public static string CamelCase(this string source);
public static string PascalCase(this string source);
public static string SnakeCase(this string source);
public static string KebabCase(this string source);
public static string UrlEncode(this string source);
public static string HtmlEncode(this string source);
public static string XmlEncode(this string source);
public static string JsonEscape(this string source);
public static string CSharpEscape(this string source);
public static string Wrap(this string source, int width);
public static string Ellipsis(this string source, int length);
public static string Truncate(this string source, int length);
public static string Truncate(this string source, int length, string suffix);
Import the child namespace explicitly:
import Global.DirectSharp.Text
Automatic root DirectSharp import does not import its children. Layout widths/lengths are Integer/System.Int32; Long configuration values require deliberate validation/conversion, with no Long overload or implicit narrowing. Ordinary extension lookup applies; qualify the intended static member when equally applicable imported candidates are ambiguous. No hidden helper priority is introduced.
| Family | Selected calls | Profile |
|---|---|---|
| Casing | Upper, Lower, CamelCase, PascalCase, SnakeCase, KebabCase | Invariant Upper/Lower and shared case/acronym segmentation |
| Encoding/escaping | UrlEncode, HtmlEncode, XmlEncode, JsonEscape, CSharpEscape | URI components, native HTML data, checked XML element-text fragments, strict JSON/C# contents |
| Layout | Wrap(width), Ellipsis(length), Truncate(length), Truncate(length, suffix) | Text-element units, total suffix budget, greedy word wrapping and strict validation |
The profiles below determine each member's behavior. No additional overload, arbitrary template-rendering API or unnamed cleanup-helper family is selected. Escaping contents and serializing an object remain different operations.
Upper/Lower use native ToUpperInvariant/ToLowerInvariant semantics, with an ArgumentNullException source guard and empty preserved. They add no trimming, normalization or whole-String scalar validation. Their Unicode tables follow the runtime, independent of the current culture. For example, Lower("FILE") is file and Upper("istanbul") is ISTANBUL even under Turkish current culture. Native culture-specific display APIs remain available explicitly.
CamelCase/PascalCase/SnakeCase/KebabCase share the segmentation rule: Unicode letters/digits and attached combining marks form words; separators produce no empty words; lowercase-or-digit-to-uppercase transitions and acronym endings split words. Digits remain with the preceding word. Transform with invariant simple casing and no normalization/transliteration. Missing source throws ArgumentNullException, malformed UTF-16 throws ArgumentException, and empty/separator-only input returns empty text. This transforms text, without promising a valid source identifier or locale-sensitive title casing.
| Input | SnakeCase | CamelCase | PascalCase |
|---|---|---|---|
| HTTPServer2ID | http_server2_id | httpServer2Id | HttpServer2Id |
| first-name | first_name | firstName | FirstName |
UrlEncode applies Uri.EscapeDataString after a source-null ArgumentNullException guard. Empty stays empty; all input is one component's data. The input a b/c becomes a%20b%2Fc, while a%20b becomes a%2520b. It does not preserve full-URL separators, decode existing percent escapes or perform form encoding. Invalid-input/escaping behavior otherwise follows that native API.
JsonEscape/CSharpEscape return escaped contents without surrounding quotes. Missing source throws ArgumentNullException and empty produces empty contents. For ASCII input containing A, a double quote, B and a line feed, the contents are illustrated below; these are output characters, not DirectSharp source escapes:
Input: A"B<LF>
Output: A\"B\n
The selected content profile validates the entire UTF-16 source before returning: isolated surrogates throw ArgumentException, including in otherwise readable text. Escape quote/backslash and use short escapes for backspace, form feed, LF, CR and tab. Encode remaining U+0000–001F, all U+007F–009F and U+2028/U+2029 as four-digit uppercase backslash-u escapes. Preserve other valid scalars, supplementary pairs, solidus and single quote without normalization. Thus café and 😀 remain readable, while U+2028 becomes the six output characters backslash-u-2028.
The targets are JSON double-quoted contents and ordinary C# double-quoted contents. Do not substitute an object serializer or treat the output as C# raw/verbatim/interpolated source, a JavaScript expression or HTML-safe script output. ASCII markup remains unescaped. HtmlEncode/XmlEncode have the separate profiles below. Ordinary String storage remains UTF-16 throughout.
HTML and XML text profiles
HtmlEncode rejects missing source with ArgumentNullException, then applies System.Net.WebUtility.HtmlEncode. Empty stays empty. Preserve that native API's Unicode/escaping behavior without adding strict scalar validation or normalization. Its targets are HTML text and quoted HTML attribute data; it does not encode JavaScript, CSS or a URI component.
XmlEncode rejects missing source with ArgumentNullException, then buffers XmlWriter.WriteString with ConformanceLevel.Fragment, OmitXmlDeclaration=true, CheckCharacters=true and NewLineHandling.Entitize. Return only the encoded element-text contents, with empty input producing empty text. Preserve native XML character/UTF-16 validation failures; invalid XML characters or isolated surrogates throw ArgumentException. Carriage returns are entitized so an XML reader reconstructs the original value. This profile is for XML element text, not an attribute encoder or a complete document.
Neither helper detects/decodes existing entities: input & becomes &amp;. Use writer structural/attribute methods for XML tags and attributes, and pass original values to frameworks that already encode them. Destination-specific examples and exact C# patterns show URI-versus-HTML composition, XML fragment round trips and native failure cases.
Layout units, budgets and wrapping
Wrap/Truncate/Ellipsis measure System.Globalization.StringInfo text elements using the target runtime's Unicode segmentation. A supplementary emoji or a base letter plus its combining accent is retained as a complete recognized element. No normalization is performed. This is not a count of display columns or database bytes; ordinary String indexing remains UTF-16.
Truncation includes the suffix within the budget. Within-budget source is unchanged. Otherwise retain a source prefix after reserving suffix space; when the suffix alone is too long, return its fitting prefix without source content. Plain Truncate uses an empty suffix, and Ellipsis uses Unicode.Ellipsis. Zero length is valid and returns empty text.
| Input / request | Result |
|---|---|
| ABCDE, Ellipsis length 4 | ABC… |
| ABCDE, Truncate length 3 with suffix [more] | [mo |
| ABC, Ellipsis length 3 | ABC |
| ABC, Ellipsis length 0 | Empty String |
| U+0065 + U+0301 + X, plain Truncate length 1 | U+0065 + U+0301, without splitting the accented element |
Wrap greedily packs words separated by ASCII space/tab, normalizing separator runs to one space and omitting line-edge separators. Split oversized words only at text-element boundaries; a final short piece can share a line with later words. Preserve existing CRLF/CR/LF exactly, including blank lines and a final boundary. Use Environment.NewLine for newly inserted boundaries. Other whitespace, including NBSP, stays word content. For example, width 7 wraps red blue green as red, blue and green on separate lines; width 4 wraps abcdefgh into abcd and efgh. Empty input stays empty and an all-space/tab line becomes empty.
Validation precedes a successful result: reject null source first, then negative truncation length/nonpositive wrap width, then a supplied null suffix. Empty suffix is valid. Validate complete source and supplied suffix UTF-16 even when a zero budget, unused suffix or discarded tail would hide malformed units. Null throws ArgumentNullException, invalid numeric bounds ArgumentOutOfRangeException and malformed UTF-16 ArgumentException. There is no clamping, replacement or Try variant. The normative profiles and C# strategies/cases retain those boundaries under the selected Integer signatures.
Numeric and formatting call shapes
| Recorded form | Contract that a C# implementation must preserve |
|---|---|
| Round(x), Round(x, digits) | Midpoints away from zero by default, unlike default Math.Round |
| Round(x, digits, mode) | Explicit ordinary .NET MidpointRounding value |
| Truncate(x) | Discard fractional part toward zero |
| Floor(x), Ceiling(x) | Corresponding lower/upper integral value under the numeric contract |
| Interpolation formats | Once-only expressions; current culture normally; nothing contributes empty text |
| Binary hex/base64/UTF-8/ASCII formats | Interpret already-supplied bytes; never implicitly read an arbitrary Stream |
The following are the twelve selected members of the root public static class DirectSharp.Numbers, using ordinary System.MidpointRounding:
public static decimal Round(decimal value);
public static decimal Round(decimal value, int digits);
public static decimal Round(decimal value, int digits, MidpointRounding mode);
public static double Round(double value);
public static double Round(double value, int digits);
public static double Round(double value, int digits, MidpointRounding mode);
public static decimal Truncate(decimal value);
public static double Truncate(double value);
public static decimal Floor(decimal value);
public static double Floor(double value);
public static decimal Ceiling(decimal value);
public static double Ceiling(double value);
Round(value) uses zero digits; without explicit mode, use AwayFromZero. Explicit mode calls the corresponding typed Math.Round overload. Digits are Integer, with native Decimal 0–28/Double 0–15 argument/failure behavior. Truncate/Floor/Ceiling preserve the argument's numeric type rather than returning Long. Double NaN/infinity and binary representation retain native typed Math behavior; helpers do not add decimal accuracy to a binary value.
No Integer/Long/Single-specific or nullable overload, extra conversion priority or arithmetic-default substitution for method arguments is selected. Ordinary widening/binding applies. An argument equally convertible to Decimal and Double can require an explicitly typed local/conversion; do not silently select a family. Ordinary imported Math keeps its own defaults: Math.Round(2.5m) is 2, while Numbers.Round(2.5m) is 3.
Qualified Numbers.Round(amount, 2) uses ordinary type/member lookup, with automatic root import or an explicit root import. The recorded bare Round/Truncate/Floor/Ceiling source forms still require their compiler binding account: a containing static class is not an implicit static import. No static-import grammar, hidden collision priority or qualified-only replacement of those source forms is selected here. See the numeric rules.
Service lookup
ServiceScope and root-safe ServiceProvider expose these selected member fragments, assuming ordinary System.Collections.Generic names. No additional generic constraints are selected here:
public T GetService<T>();
public T GetService<T>(object key);
public IReadOnlyList<T> GetAllServices<T>();
public IReadOnlyList<T> GetAllServices<T>(object key);
public bool HasService<T>();
public bool HasService<T>(object key);
| Lookup case | Required observation |
|---|---|
| Missing required singular registration | DirectSharp.ServiceNotFoundException |
| No matches for plural lookup | Present empty IReadOnlyList |
| Keyed call with null | ArgumentNullException before lookup/activation; use no-key overload for unkeyed identity |
| Keyed value with different type/case | Exact declared key identity; do not normalize it through source identifier rules |
| Activation throws | Preserve activation failure; do not relabel it as missing registration |
| Plural activation fails partway | Failure at the call; no successful partial list, rollback or ownership transfer |
| Reuse a plural result | Same resolved instances; do not activate transients again by enumerating it |
| Disposed/invalid scope or root-safety violation | Preserve that failure category, rather than report missing registration |
DirectSharp.ServiceNotFoundException derives from InvalidOperationException. ServiceType is a read-only System.Type; ServiceKey is a read-only nullable Object, null for an unkeyed request. The selected constructors are:
public ServiceNotFoundException(Type serviceType, object? serviceKey = null);
public ServiceNotFoundException(Type serviceType, object? serviceKey,
string? message, Exception? innerException);
A null serviceType throws ArgumentNullException. A null serviceKey means unkeyed exception metadata, distinct from an invalid null keyed-lookup argument. Identity is retained without normalization. A null message selects a useful default; callers must not parse a particular English sentence as an API. The detailed overload retains the supplied inner exception. There is no parameterless/message-only constructor or formatter-based serialization constructor/contract. Lookup still uses this exception only for an unregistered required singular identity.
Portable service names and native hosts
| Source surface | Established meaning | CLR/native boundary |
|---|---|---|
| provider.CreateScope() | Independent explicitly owned scope | Public factory/constructor machinery is separate from the source form |
| scopeFactory.Create() | Narrow scope-creation capability | Every compatible provider supplies the capability without manual registration |
| provider/scope/main-provider Native | Native interoperability escape hatch | Exact native return/adapter types remain backend-specific |
| MainServiceProvider.Set(provider) | Appoint an existing provider without taking ownership | One active main provider; no hidden ambient current scope |
| MainServiceProvider.CreateScope() | Create a scope through the appointed provider | Missing main provider is an infrastructure failure |
| Composition Create | Build an independent provider deliberately | Conceptual source form; backend-defined emitted API shape |
| Composition Register | Contribute registrations to an existing host registry | Must not create a second provider behind the host |
| ServiceRegistry | Advanced/native registration escape hatch | Opaque external registration can limit static graph analysis |
Retrieved services and needs remain borrowed. Owning provider/scope cleanup controls created-service lifetimes. Returning IReadOnlyList does not freeze service state or extend a scope. A native bridge must preserve exact keys, no-activation availability checks where supported, root/scope restrictions and native host shutdown ownership. An arbitrary IServiceProvider alone cannot establish every registration/graph fact; diagnostics must distinguish known contracts from opaque integration. The native integration matrix gives concrete mapping and failure cases. The ordinary Microsoft DI host remains the first application path.
Compile-time declarations and private support
Feature declarations and wrapper applications use the selected declaration catalogue. Their wire metadata, template-engine host ABI and private lowered helpers are not public application-facing factory methods. Likewise, Gate's concrete permit, collected-list implementation and default/lazy/concurrent state machines are private implementation choices under the observable contracts. Package names, target frameworks and exported native integration declarations must not be inferred from a reference helper class.