Table of Contents

Class DType

Namespace
NumSharp
Assembly
NumSharp.dll

NumSharp's data-type descriptor — the INSTANCE of a DTypeMeta class, standing in for NumPy's numpy.dtype object (np.dtype('f8'), np.dtype('M8[ns]')), and the single dtype spelling every dtype-taking API in NumSharp accepts.

public sealed class DType : IEquatable<DType>
Inheritance
DType
Implements
Inherited Members

Remarks

Two levels (NEP 41/42). The CLASS (Metanp.dtypes.Float64DType) owns the behaviour: promotion, casting, the default instance; the INSTANCE owns the parameters: byteorder and, for the parametric datetime pair, the unit (DatetimeMetadata). The 15 storage-backed builtins have one canonical instance each (np.dtype("i8") is the same object every time — isbuiltin == 1); a datetime descriptor or a non-native-byte-order one is a fresh object (isbuiltin == 0), exactly as in NumPy.

Why it exists. NumPy funnels every dtype= argument through one coercion point, numpy.dtype(...), so a Python type (float), a NumPy scalar type (np.float32), a np.dtype instance and a dtype string ('float32', 'f4', '<f8') are ALL valid there. NumSharp historically had three separate spellings — a C# Type, an NPTypeCode enum, and this descriptor from dtype(string) — which forced two-or-three overloads per function. DType collapses them: it is the one type every dtype-taking overload accepts, and each of the other spellings converts to it IMPLICITLY, so a caller writes whichever is convenient and it binds the single overload — mirroring NumPy's one dtype=.

The four spellings, all implicit. The following are equivalent and all bind the one DType overload (e.g. np.sqrt(x, dtype: …)):

<ul><li><b><xref href="System.Type" data-throw-if-not-resolved="false"></xref></b> — <code>typeof(float)</code> (NumPy's Python/NumPy scalar type).</li><li><b><xref href="NumSharp.NPTypeCode" data-throw-if-not-resolved="false"></xref></b> — <code>NPTypeCode.Single</code> (NumSharp's compact storage enum; no NumPy counterpart).</li><li><b>NumPy dtype string</b> — <code>"float32"</code> / <code>"f4"</code> / <code>"<f8"</code> / <code>"M8[ns]"</code> (NumPy's <code>dtype='float32'</code> — see the casing rules below).</li><li><b><xref href="NumSharp.DType" data-throw-if-not-resolved="false"></xref> itself</b> — <code>DType.Single</code>, <code>np.dtype("f4")</code>, <code>DType.From(...)</code>.</li></ul>

A <xref href="NumSharp.DType" data-throw-if-not-resolved="false"></xref> also converts back to <xref href="System.Type" data-throw-if-not-resolved="false"></xref> and <xref href="NumSharp.NPTypeCode" data-throw-if-not-resolved="false"></xref>
implicitly, so it drops straight into code expecting either — as long as its class has storage: a
datetime descriptor has none yet (Stage A), and converting one raises <xref href="System.NotSupportedException" data-throw-if-not-resolved="false"></xref>
rather than silently degrading to the "infer" state.

None / infer is null. A null DType is the "none/infer" state — the analog of NumPy's dtype=None. This is precisely why DType is a class, not a struct: a nullable DType dtype = null parameter is a drop-in replacement for the old Type dtype = null parameter, so the engine's existing null idioms keep working verbatim — dtype?.GetTypeCode() yields NPTypeCode? (null when none) and dtype == null tests the none state. Converting a null/Empty spelling yields a null DType (never a throwing conversion); the explicit DType(Type) / DType(NPTypeCode) constructors, by contrast, reject null/Empty (use a null DType for none).

NumPy string casing (source of truth: NumPy 2.4.2). Strings are parsed by dtype(string) with NumPy's exact, case-sensitive grammar — the single-character codes differ by case:

<table><thead><tr><th class="term">code</th><th class="description">type</th></tr></thead><tbody><tr><td class="term">?</td><td class="description">bool</td></tr><tr><td class="term">b / B</td><td class="description">int8 / uint8</td></tr><tr><td class="term">h / H</td><td class="description">int16 / uint16</td></tr><tr><td class="term">i / I</td><td class="description">int32 / uint32</td></tr><tr><td class="term">q / Q</td><td class="description">int64 / uint64</td></tr><tr><td class="term">e / f / d</td><td class="description">float16 / float32 / float64</td></tr><tr><td class="term">D</td><td class="description">complex128</td></tr><tr><td class="term">M8[unit] / m8[unit]</td><td class="description">datetime64 / timedelta64 (descriptor-level in Stage A)</td></tr></tbody></table>

Sized forms (<code>"i4"</code>, <code>"f8"</code>, <code>"c16"</code>), lowercase names (<code>"float64"</code>, <code>"int32"</code>,
<code>"complex128"</code>, <code>"datetime64[ns]"</code>) and byte-order prefixes (<code>"<f8"</code>, <code>">i4"</code>,
<code>"=u2"</code>, <code>"|b1"</code>) are all accepted; a non-native prefix (<code>">i4"</code> on this little-endian host) is
KEPT on the descriptor (<xref href="NumSharp.DType.byteorder" data-throw-if-not-resolved="false"></xref> <code>'>'</code>, <xref href="NumSharp.DType.isnative" data-throw-if-not-resolved="false"></xref> false) as NumPy does.

Deliberately narrowed to NumSharp's capability (the same narrowing as dtype(string)): only NumSharp's 15 element types can back an array. Three consequences differ from NumPy and are intentional — (1) complex64 ('F', "c8", "complex64") is rejected with NotSupportedException (NumSharp has only complex128), as are structured / void / object / (byte)string dtypes; (2) NumSharp additionally accepts a superset of NumPy's casing — the C# / NPTypeCode PascalCase names ("Int32", "Single", "Boolean", "SByte", "Decimal", "Char") that NumPy 2.4.2 rejects — as a convenience for C# callers; (3) datetime64/timedelta64 descriptors exist (parse, format, promote, cast-check) but cannot allocate storage yet.

Descriptor surface (mirrors numpy.dtype): type (the C# Type), typecode (NPTypeCode), Meta, num, name, kind ('b'/'i'/'u'/'f'/'c'/'M'/'m'), char, itemsize, alignment, byteorder, str, descr, isbuiltin, isnative, hasobject, flags, metadata, newbyteorder(string). Equality is structural (class + byte order + parameters) and null-safe; Equals(object) additionally coerces a Type, an NPTypeCode or a dtype string the way np.dtype('i4') == 'i4' does. ToString() is NumPy's str(dtype) (int32, >i4, datetime64[ns]); ToString(bool) with repr: true is repr(dtype) (dtype('int32'), dtype('<M8[ns]')).

np.sqrt(x, dtype: typeof(float));      // Type
np.sqrt(x, dtype: NPTypeCode.Single);  // NPTypeCode enum
np.sqrt(x, dtype: "float32");          // NumPy string  (== NumPy's dtype='float32')
np.sqrt(x, dtype: DType.Single);       // DType spelling
np.sqrt(x);                            // dtype omitted  == None / infer

DType d = np.dtype("<f8"); // full descriptor: d.type==typeof(double), d.kind=='f', d.itemsize==8 Type t = DType.Double; // implicit DType -> Type NPTypeCode c = (DType)"int32"; // implicit string -> DType -> NPTypeCode bool same = DType.Single == (DType)"f4"; // true — structural equality DType m = np.dtype("M8[10ns]"); // datetime64[10ns]: m.kind=='M', np.datetime_data(m) == ("ns", 10)

Constructors

DType(NPTypeCode)

Builds a fresh descriptor for an NPTypeCode — a COPY of the class's canonical instance (prefer From(NPTypeCode) / the implicit conversion, which return the singleton itself). For the "none/infer" state use a null DType (this ctor throws on Empty; the implicit NPTypeCodeDType conversion yields null).

public DType(NPTypeCode typecode)

Parameters

typecode NPTypeCode

DType(Type)

Builds a fresh descriptor for a C# Type — a COPY of the class's canonical instance (prefer From(Type) / the implicit conversion, which return the singleton itself). For the "none/infer" state use a null DType (this ctor throws on a null type; the implicit TypeDType conversion yields null).

public DType(Type type)

Parameters

type Type

Fields

NativeByteOrder

NumPy's '=': the byte order of this host.

public const char NativeByteOrder = '='

Field Value

char

NotApplicableByteOrder

NumPy's '|': byte order is not applicable (single-byte types).

public const char NotApplicableByteOrder = '|'

Field Value

char

byteorder

A character indicating the byte-order of this data-type object: '=' native, '<' little-endian, '>' big-endian, '|' not applicable (single-byte types). Only the NON-native order is ever stored explicitly (NumPy normalises the host's own order to '=').

public readonly char byteorder

Field Value

char

itemsize

The size of the dtype in bytes (itemsize).

public readonly int itemsize

Field Value

int

kind

A character code (one of ‘biufcmMOSUV’) identifying the general kind of data: b boolean, i signed integer, u unsigned integer, f floating-point, c complex floating-point, m timedelta, M datetime, O object, S (byte-)string, U Unicode, V void.

public readonly char kind

Field Value

char

name

NumPy's dtype.name spelling ("float32", "int64", "bool", "complex128", "datetime64[ns]") — the CLR Type.Name ("Single") is not a NumPy name and does not round-trip through dtype(string). The NumSharp-only dtypes have no NumPy analog and get lowercase names of their own ("decimal", "char") rather than the nearest NumPy stand-in.

public readonly string name

Field Value

string

type

The C# scalar type of one element (NumPy's dtype.type); null for a class with no C# scalar yet (datetime64 in Stage A).

public readonly Type type

Field Value

Type

typecode

The NumSharp storage discriminator; Empty for a class without storage (datetime64 in Stage A).

public readonly NPTypeCode typecode

Field Value

NPTypeCode

Properties

Boolean

The bool descriptor.

public static DType Boolean { get; }

Property Value

DType

Byte

The byte (uint8) descriptor.

public static DType Byte { get; }

Property Value

DType

Char

The char descriptor.

public static DType Char { get; }

Property Value

DType

Complex

The Complex (complex128) descriptor.

public static DType Complex { get; }

Property Value

DType

DatetimeMetadata

The instance parameters of a datetime64/timedelta64 descriptor (NumPy's c_metadata); null for every other class.

public DatetimeMetaData? DatetimeMetadata { get; }

Property Value

DatetimeMetaData?

Decimal

The decimal descriptor.

public static DType Decimal { get; }

Property Value

DType

Double

The double (float64) descriptor.

public static DType Double { get; }

Property Value

DType

Half

The Half (float16) descriptor.

public static DType Half { get; }

Property Value

DType

HostByteOrder

The explicit character of this host's byte order ('<' on little-endian machines) — what str renders for a native descriptor.

public static char HostByteOrder { get; }

Property Value

char

Int16

The short descriptor.

public static DType Int16 { get; }

Property Value

DType

Int32

The int descriptor.

public static DType Int32 { get; }

Property Value

DType

Int64

The long descriptor.

public static DType Int64 { get; }

Property Value

DType

Meta

The DType CLASS this descriptor instantiates (type(np.dtype('f8'))): np.dtypes.Float64DType.

public DTypeMeta Meta { get; }

Property Value

DTypeMeta

SByte

The sbyte (int8) descriptor.

public static DType SByte { get; }

Property Value

DType

Single

The float (float32) descriptor.

public static DType Single { get; }

Property Value

DType

SwappedByteOrder

The character of the OTHER byte order ('>' on little-endian machines) — what a non-native descriptor carries.

public static char SwappedByteOrder { get; }

Property Value

char

UInt16

The ushort descriptor.

public static DType UInt16 { get; }

Property Value

DType

UInt32

The uint descriptor.

public static DType UInt32 { get; }

Property Value

DType

UInt64

The ulong descriptor.

public static DType UInt64 { get; }

Property Value

DType

alignment

The required alignment (bytes) of this data-type (dtype.alignment).

public int alignment { get; }

Property Value

int

base

dtype.base: the base of a sub-array dtype — this descriptor itself.

public DType @base { get; }

Property Value

DType

char

A unique character code for each of the built-in types ('?' 'b' 'B' 'h' 'H' 'i' 'I' 'l' 'L' 'e' 'f' 'd' 'D' 'M' 'm').

public char @char { get; }

Property Value

char

descr

The array-interface description (dtype.descr): one unnamed field carrying str[('', '<i4')].

public IReadOnlyList<(string name, string typestr)> descr { get; }

Property Value

IReadOnlyList<(string name, string typestr)>

fields

dtype.fields: always null (no structured dtypes).

public IReadOnlyDictionary<string, (DType, int)> fields { get; }

Property Value

IReadOnlyDictionary<string, (DType, int)>

flags

dtype.flags: the item flags (NumPy's NPY_ITEM_REFCOUNT | NPY_NEEDS_INIT | … = 63 for a reference-holding dtype, 0 otherwise).

public int flags { get; }

Property Value

int

hasobject

dtype.hasobject: whether items hold references that need clearing (false for every current class).

public bool hasobject { get; }

Property Value

bool

isbuiltin

dtype.isbuiltin: 1 for the canonical instance of a builtin class, 2 for a user-defined class (the NumSharp-only Decimal/Char), 0 for any other instance — a datetime descriptor, a non-native byte order, or a copy made with the public constructors.

public int isbuiltin { get; }

Property Value

int

isnative

dtype.isnative: true unless the byte order is explicitly the non-host one.

public bool isnative { get; }

Property Value

bool

metadata

dtype.metadata: user metadata (never set in NumSharp — always null).

public object metadata { get; }

Property Value

object

names

dtype.names: always null (no structured dtypes).

public string[] names { get; }

Property Value

string[]

ndim

dtype.ndim: the sub-array rank — always 0.

public int ndim { get; }

Property Value

int

num

NumPy's unique type number (dtype.num).

public int num { get; }

Property Value

int

shape

dtype.shape: the sub-array shape — always empty (no sub-array dtypes).

public int[] shape { get; }

Property Value

int[]

str

The array-interface typestring (dtype.str): explicit byte order, kind and size — "<i4", "|b1", ">f8", "<M8[ns]", "<m8".

public string str { get; }

Property Value

string

subdtype

dtype.subdtype: always null (no sub-array dtypes).

public (DType, int[])? subdtype { get; }

Property Value

(DType, int[])?

Methods

Equals(DType)

Structural equality: the same class, byte order and instance parameters (M8[ns] != M8[s], >i4 != i4).

public bool Equals(DType other)

Parameters

other DType

Returns

bool

Equals(NPTypeCode)

Coercing equality with an NPTypeCode; Empty is unequal.

public bool Equals(NPTypeCode typecode)

Parameters

typecode NPTypeCode

Returns

bool

Equals(object)

NumPy's coercing dtype.eq: the operand is converted to a descriptor first, so a Type (typeof(int)), an NPTypeCode or a dtype string ("i4", "int32") compare equal to the descriptor they denote; anything that is not a dtype (a bad string, a DTypeMeta class object, null) compares unequal without raising.

public override bool Equals(object obj)

Parameters

obj object

Returns

bool

Equals(string)

Coercing equality with a dtype STRING (np.dtype('i4') == 'i4'): an unparseable string is simply unequal (np.dtype('i4') == 'garbage' is False, not an error). This overload exists because a string would otherwise bind Equals(DType) through the implicit string→DType conversion, which raises on a bad string.

public bool Equals(string dtype)

Parameters

dtype string

Returns

bool

Equals(Type)

Coercing equality with a C# Type (np.dtype('i4') == np.int32); a non-NumSharp type is unequal.

public bool Equals(Type type)

Parameters

type Type

Returns

bool

From(NPTypeCode)

The descriptor of an NPTypeCode — the class's canonical instance.

public static DType From(NPTypeCode typecode)

Parameters

typecode NPTypeCode

Returns

DType

From(string)

Builds a descriptor from a NumPy dtype string (NumPy's case-sensitive grammar). Same as dtype(string).

public static DType From(string dtype)

Parameters

dtype string

Returns

DType

From(Type)

The descriptor of a C# Type — the class's canonical instance (np.dtype(typeof(int))).

public static DType From(Type type)

Parameters

type Type

Returns

DType

GetHashCode()

Consistent with Equals(DType): the class and byte order, not the parameters (NumPy: hash(M8[ns]) == hash(M8[s])).

public override int GetHashCode()

Returns

int

GetTypeCode()

Returns this descriptor's NPTypeCode. Combined with a nullable DType this keeps the old Type dtype idiom drop-in: dtype?.GetTypeCode() yields NPTypeCode? (null for the none/infer state where dtype == null).

public NPTypeCode GetTypeCode()

Returns

NPTypeCode

Exceptions

NotSupportedException

The class has no storage yet (a datetime64/timedelta64 descriptor in Stage A).

ToString()

NumPy's str(dtype): the name for a native descriptor (int32, datetime64[ns], decimal), the typestring for a non-native or flexible one (>i4).

public override string ToString()

Returns

string

ToString(bool)

repr false: str(dtype). repr true: NumPy's repr(dtype)dtype('int32'), dtype('bool'), dtype('>i4'), dtype('<M8[ns]'), and for the NumSharp-only user-range classes NumPy's unquoted user form dtype(decimal).

public string ToString(bool repr)

Parameters

repr bool

Returns

string

newbyteorder(char)

public DType newbyteorder(char new_order)

Parameters

new_order char

Returns

DType

newbyteorder(string)

Return a new dtype with a different byte order (NumPy's dtype.newbyteorder).

public DType newbyteorder(string new_order = "S")

Parameters

new_order string

Byte order to force. The default ('S') swaps the current byte order. Codes (first letter, case-insensitive): 'S' swap; '<'/'L'/'little' little-endian; '>'/'B'/'big' big-endian; '='/'N'/'native' native; '|'/'I'/'ignore' no change.

Returns

DType

A new descriptor with the requested byte order (single-byte classes are unaffected).

Exceptions

ValueError

byteorder not recognized (got '…').

Operators

operator ==(DType, DType)

Structural equality (null-safe).

public static bool operator ==(DType left, DType right)

Parameters

left DType
right DType

Returns

bool

explicit operator Type(DType)

A descriptor converts back to its Type (none/null ⇒ null) — EXPLICITLY: (Type)a.dtype, or the NumPy field a.dtype.type. It is deliberately not implicit, because Type declares its own ==: with conversions in BOTH directions, a.dtype == typeof(double) would be ambiguous between Type.== and DType.== (CS0034), and adding ==(DType, Type) overloads instead would make descr == null ambiguous (neither target is better). With only the TypeDType direction implicit, a.dtype == typeof(double), typeof(double) == a.dtype, Assert.AreEqual(typeof(double), a.dtype) (T infers as DType) and a.dtype.Should().Be(typeof(double)) all resolve to the structural, coercing DType equality.

public static explicit operator Type(DType dtype)

Parameters

dtype DType

Returns

Type

Exceptions

NotSupportedException

The class has no C# storage type yet (datetime64/timedelta64 in Stage A).

operator >(DType, DType)

NumPy's dtype > other: not equal, and right casts safely to left.

public static bool operator >(DType left, DType right)

Parameters

left DType
right DType

Returns

bool

operator >=(DType, DType)

NumPy's dtype >= other: right casts safely to left.

public static bool operator >=(DType left, DType right)

Parameters

left DType
right DType

Returns

bool

implicit operator NPTypeCode(DType)

A descriptor converts back to its NPTypeCode (none/nullEmpty).

public static implicit operator NPTypeCode(DType dtype)

Parameters

dtype DType

Returns

NPTypeCode

Exceptions

NotSupportedException

The class has no storage yet (datetime64/timedelta64 in Stage A).

implicit operator DType(NPTypeCode)

An NPTypeCode converts to its canonical descriptor (Empty ⇒ none).

public static implicit operator DType(NPTypeCode typecode)

Parameters

typecode NPTypeCode

Returns

DType

implicit operator DType(NPTypeCode?)

A nullable NPTypeCode converts to a descriptor (null/Empty ⇒ none).

public static implicit operator DType(NPTypeCode? typecode)

Parameters

typecode NPTypeCode?

Returns

DType

implicit operator DType(string)

A NumPy dtype string converts to a descriptor via dtype(string) — NumPy's exact, case-sensitive spelling ("f4", "float32", "<f8", "M8[ns]"). null ⇒ none.

public static implicit operator DType(string dtype)

Parameters

dtype string

Returns

DType

implicit operator DType(Type)

A C# Type converts to its canonical descriptor (null ⇒ none).

public static implicit operator DType(Type type)

Parameters

type Type

Returns

DType

operator !=(DType, DType)

Structural inequality (null-safe).

public static bool operator !=(DType left, DType right)

Parameters

left DType
right DType

Returns

bool

operator <(DType, DType)

NumPy's dtype < other: strictly promotes — not equal, and left casts safely to right.

public static bool operator <(DType left, DType right)

Parameters

left DType
right DType

Returns

bool

operator <=(DType, DType)

NumPy's dtype <= other: left casts safely to right.

public static bool operator <=(DType left, DType right)

Parameters

left DType
right DType

Returns

bool