Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
.NET 7 führt neue mathematische generische Schnittstellen in die Basisklassenbibliothek ein. Die Verfügbarkeit dieser Schnittstellen bedeutet, dass Sie einen Typparameter eines generischen Typs oder einer methode auf "zahlähnliche" beschränken können. Darüber hinaus können Sie mit C# 11 und höher static virtual
definieren. Da Operatoren als static
deklariert werden müssen, ermöglicht es dieses neue C#-Feature, dass Operatoren in den neuen Schnittstellen für nummernähnliche Typen deklariert werden können.
Diese Innovationen ermöglichen es Ihnen, mathematische Vorgänge generisch durchzuführen, d. h., ohne den genauen Typ kennen zu müssen, mit dem Sie arbeiten. Wenn Sie beispielsweise eine Methode schreiben möchten, die zwei Zahlen hinzufügt, mussten Sie zuvor eine Überladung der Methode für jeden Typ hinzufügen (z. B. static int Add(int first, int second)
und static float Add(float first, float second)
). Jetzt können Sie eine einzelne generische Methode schreiben, bei der der Typparameter auf einen zahlenähnlichen Typ beschränkt ist. Beispiel:
static T Add<T>(T left, T right)
where T : INumber<T>
{
return left + right;
}
Bei dieser Methode ist der Typparameter T
auf einen Typ beschränkt, der die neue INumber<TSelf> Schnittstelle implementiert.
INumber<TSelf> implementiert die IAdditionOperators<TSelf,TOther,TResult> Schnittstelle, die den Operator +enthält. Dies ermöglicht es der Methode, die beiden Zahlen generisch hinzuzufügen. Die Methode kann mit allen eingebauten numerischen Typen von .NET verwendet werden, da sie alle aktualisiert wurden, um INumber<TSelf> in .NET 7 zu implementieren.
Bibliotheksautoren profitieren am meisten von den generischen mathematischen Schnittstellen, da sie ihre Codebasis vereinfachen können, indem sie "redundante" Überladungen entfernen. Andere Entwickler profitieren indirekt, da die von ihnen genutzten APIs mit der Unterstützung weiterer Typen beginnen können.
Die Schnittstellen
Die Schnittstellen wurden so konzipiert, dass sie so fein abgestimmt sind, dass Benutzer ihre eigenen Schnittstellen oben definieren können, während sie auch präzise genug sind, um sie einfach zu nutzen. In diesem Zusammenhang gibt es einige wichtige numerische Schnittstellen, mit denen die meisten Benutzer interagieren, wie INumber<TSelf> und IBinaryInteger<TSelf>. Die feineren Schnittstellen, wie IAdditionOperators<TSelf,TOther,TResult> und ITrigonometricFunctions<TSelf>, unterstützen diese Typen und sind für Entwickler verfügbar, die ihre eigenen domänenspezifischen numerischen Schnittstellen definieren.
- Numerische Schnittstellen
- Operatorschnittstellen
- Funktionsschnittstellen
- Analysieren und Formatieren von Schnittstellen
Numerische Schnittstellen
In diesem Abschnitt werden die Schnittstellen in System.Numerics beschrieben, die nummernähnliche Typen und die für sie verfügbaren Funktionen umfassen.
Schnittstellenname | BESCHREIBUNG |
---|---|
IBinaryFloatingPointIeee754<TSelf> | Stellt APIs bereit, die für binäre Gleitkommatypen1 gemeinsam sind und den IEEE 754-Standard implementieren. |
IBinaryInteger<TSelf> | Macht APIs verfügbar, die für binäre ganze Zahlen2 gemeinsam sind. |
IBinaryNumber<TSelf> | Macht APIs verfügbar, die für Binäre Zahlen üblich sind. |
IFloatingPoint<TSelf> | Macht APIs verfügbar, die für Gleitkommatypen gemeinsam sind. |
IFloatingPointIeee754<TSelf> | Macht APIs verfügbar, die üblicherweise für Gleitkommatypen verwendet werden, die den IEEE 754-Standard implementieren. |
INumber<TSelf> | Macht APIs verfügbar, die für vergleichbare Zahlentypen (effektiv die Domäne der realen Zahl) gemeinsam sind. |
INumberBase<TSelf> | Macht APIs verfügbar, die allen Nummerntypen gemeinsam sind (effektiv die "komplexe" Nummerndomäne). |
ISignedNumber<TSelf> | Macht APIs verfügbar, die allen signierten Nummerntypen gemeinsam sind (z. B. das Konzept von NegativeOne ). |
IUnsignedNumber<TSelf> | Macht APIs verfügbar, die allen nicht signierten Nummerntypen gemeinsam sind. |
IAdditiveIdentity<TSelf,TResult> | Legt das Konzept von (x + T.AdditiveIdentity) == x offen. |
IMinMaxValue<TSelf> | Legt das Konzept von T.MinValue und T.MaxValue offen. |
IMultiplicativeIdentity<TSelf,TResult> | Legt das Konzept von (x * T.MultiplicativeIdentity) == x offen. |
1Die binären Gleitkommatypen sind Double (double
), Halfund Single (float
).
2 Die binären ganzzahligen Typen sind Byte (byte
), Int16 (short
), Int32 (int
), Int64 (long
), Int128, IntPtr (nint
), SByte (sbyte
), UInt16 (ushort
), UInt32 (uint
), UInt64 (ulong
), UInt128 und UIntPtr (nuint
).
Die Schnittstelle, die Sie am ehesten direkt verwenden, ist INumber<TSelf>, was ungefähr einer reellen Zahl entspricht. Wenn ein Typ diese Schnittstelle implementiert, bedeutet dies, dass ein Wert ein Vorzeichen hat (einschließlich unsigned
-Typen, die als positiv betrachtet werden) und mit anderen Werten desselben Typs verglichen werden kann.
INumberBase<TSelf> Es werden komplexere Konzepte wie komplexe und imaginäre Zahlen, z. B. die Quadratwurzel einer negativen Zahl, vermittelt. Weitere Schnittstellen, z. B. IFloatingPointIeee754<TSelf>, wurden erstellt, da nicht alle Vorgänge für alle Zahlentypen sinnvoll sind—z. B. ist die Berechnung des Bodenwerts einer Zahl nur für Gleitkommatypen sinnvoll. In der .NET-Basisklassenbibliothek wird Double vom Gleitkommatyp IFloatingPointIeee754<TSelf> implementiert, Int32 aber nicht.
Mehrere der Schnittstellen werden auch von verschiedenen anderen Typen implementiert, darunter Char, , DateOnly, DateTime, DateTimeOffset, Decimal, Guid, und TimeOnlyTimeSpan.
In der folgenden Tabelle sind einige der kernigen APIs aufgeführt, die von jeder Schnittstelle verfügbar gemacht werden.
Schnittstelle | API-Name | BESCHREIBUNG |
---|---|---|
IBinaryInteger<TSelf> | DivRem |
Berechnet den Quotienten und Rest gleichzeitig. |
LeadingZeroCount |
Zählt die Anzahl der führenden Nullbits in der binären Darstellung. | |
PopCount |
Zählt die Anzahl der festgelegten Bits in der binären Darstellung. | |
RotateLeft |
Rotiert Bits nach links, was manchmal auch als kreisförmige Verschiebung nach links bezeichnet wird. | |
RotateRight |
Rotiert Bits nach rechts, was manchmal auch als kreisförmige Verschiebung nach rechts bezeichnet wird. | |
TrailingZeroCount |
Zählt die Anzahl der nachfolgenden Nullbits in der binären Darstellung. | |
IFloatingPoint<TSelf> | Ceiling |
Rundet den Wert in Richtung positive Unendlichkeit. +4,5 wird +5, und -4,5 wird -4. |
Floor |
Rundet den Wert in Richtung negative Unendlichkeit. +4,5 wird +4, und -4,5 wird -5. | |
Round |
Rundet den Wert mithilfe des angegebenen Rundungsmodus ab. | |
Truncate |
Rundet den Wert auf Null. +4,5 wird +4, und -4,5 wird -4. | |
IFloatingPointIeee754<TSelf> | E |
Ruft einen Wert ab, der die Zahl von Euler für den Typ darstellt. |
Epsilon |
Ruft den kleinsten darstellbaren Wert ab, der größer als Null für den Typ ist. | |
NaN |
Ruft einen Wert ab, der NaN für den Typ darstellt. |
|
NegativeInfinity |
Ruft einen Wert ab, der -Infinity für den Typ darstellt. |
|
NegativeZero |
Ruft einen Wert ab, der -Zero für den Typ darstellt. |
|
Pi |
Ruft einen Wert ab, der Pi für den Typ darstellt. |
|
PositiveInfinity |
Ruft einen Wert ab, der +Infinity für den Typ darstellt. |
|
Tau |
Ruft einen Wert ab, der Tau (2 * Pi ) für den Typ darstellt. |
|
(Sonstige) | (Implementiert den vollständigen Satz von Schnittstellen, die unter Funktionsschnittstellen aufgeführt sind.) | |
INumber<TSelf> | Clamp |
Schränkt einen Wert auf nicht mehr und nicht weniger als den angegebenen Min- und Maximalwert ein. |
CopySign |
Legt das Vorzeichen eines angegebenen Werts so fest, dass es dasselbe ist wie das eines anderen angegebenen Werts. | |
Max |
Gibt den größeren von zwei Werten zurück, wobei NaN zurückgegeben wird, wenn eine der Eingaben NaN ist. |
|
MaxNumber |
Gibt den größeren von zwei Werten zurück, wenn eine Eingabe NaN ist, wird die Zahl zurückgegeben. |
|
Min |
Gibt den kleineren von zwei Werten zurück, wobei NaN zurückgegeben wird, wenn eine der beiden Eingaben NaN ist. |
|
MinNumber |
Gibt den kleineren von zwei Werten zurück, wobei die Zahl zurückgegeben wird, wenn eine Eingabe ist NaN . |
|
Sign |
Gibt -1 für negative Werte, 0 für Null und +1 für positive Werte zurück. | |
INumberBase<TSelf> | One |
Ruft den Wert „1“ für den Typ ab. |
Radix |
Ruft die Basis für den Typ ab. Int32 gibt 2 zurück. Decimal gibt 10 zurück. | |
Zero |
Ruft den Wert 0 für den Typ ab. | |
CreateChecked |
Erstellt einen Wert, und löst eine Überlaufausnahme (OverflowException) aus, wenn der Platz für die Eingabe nicht ausreicht.1 | |
CreateSaturating |
Erstellt einen Wert, der auf T.MinValue oder T.MaxValue begrenzt wird, wenn die Eingabe nicht passen kann.1 |
|
CreateTruncating |
Erstellt einen Wert aus einem anderen Wert, der wiederholt wird, wenn die Eingabe nicht passt. 1 | |
IsComplexNumber |
Gibt "true" zurück, wenn der Wert einen realen Teil ungleich Null und einen Nicht-Null-Imaginärteil aufweist. | |
IsEvenInteger |
Gibt true zurück, wenn der Wert eine gerade ganze Zahl ist. 2.0 gibt zurück true , und 2,2 gibt zurück false . |
|
IsFinite |
Gibt true zurück, wenn der Wert nicht unendlich ist und nicht NaN . |
|
IsImaginaryNumber |
Gibt wahr zurück, wenn der Wert einen Realteil von null hat. Das bedeutet, dass 0 imaginär ist und 1 + 1i nicht. |
|
IsInfinity |
Gibt true zurück, wenn der Wert Unendlichkeit darstellt. | |
IsInteger |
Gibt true zurück, wenn der Wert eine ganze Zahl ist. 2.0 und 3.0 geben true zurück, und 2.2 und 3.1 geben false zurück. |
|
IsNaN |
Gibt true zurück, wenn der Wert NaN repräsentiert. |
|
IsNegative |
Gibt true zurück, wenn der Wert negativ ist. Dies umfasst -0.0. | |
IsPositive |
Gibt true zurück, wenn der Wert positiv ist. Dies umfasst 0 und +0,0. | |
IsRealNumber |
Gibt true zurück, wenn der Wert einen null imaginären Teil aufweist. Dies bedeutet, dass 0 real ist, wie alle INumber<T> Arten. |
|
IsZero |
Gibt true zurück, wenn der Wert Null darstellt. Dies umfasst 0, +0,0 und -0,0. | |
MaxMagnitude |
Gibt den Wert mit einem höheren absoluten Wert zurück. Ist eine der Eingaben NaN , wird NaN zurückgegeben. |
|
MaxMagnitudeNumber |
Gibt den Wert mit einem größeren absoluten Wert zurück, wobei die Zahl zurückgegeben wird, wenn eine Eingabe ist NaN . |
|
MinMagnitude |
Gibt den Wert mit einem niedrigeren absoluten Wert zurück und gibt NaN zurück, falls eine der Eingaben NaN ist. |
|
MinMagnitudeNumber |
Gibt den Wert mit einem niedrigeren absoluten Wert zurück, wobei die Zahl zurückgegeben wird, wenn eine Eingabe ist NaN . |
|
ISignedNumber<TSelf> | NegativeOne |
Ruft den Wert „-1“ für den Typ ab. |
1Beachten Sie die folgenden Beispiele, um das Verhalten der drei Create*
Methoden zu verstehen.
Beispiel für einen Wert, der zu groß ist:
-
byte.CreateChecked(384)
löst eine OverflowException aus. -
byte.CreateSaturating(384)
gibt 255 zurück, da 384 größer als Byte.MaxValue (255) ist. -
byte.CreateTruncating(384)
gibt 128 zurück, da es die niedrigsten 8 Bits dauert (384 hat eine Hexadendarstellung von0x0180
, und die niedrigsten 8 Bits ist0x80
, was 128 ist).
Beispiel für einen Wert, der zu klein ist:
-
byte.CreateChecked(-384)
löst eine OverflowException aus. -
byte.CreateSaturating(-384)
gibt 0 zurück, da -384 kleiner als Byte.MinValue (0) ist. -
byte.CreateTruncating(-384)
gibt 128 zurück, da es die niedrigsten 8 Bits dauert (384 hat eine Hexadendarstellung von0xFE80
, und die niedrigsten 8 Bits ist0x80
, was 128 ist).
Die Create*
Methoden weisen auch einige besondere Aspekte für IEEE 754-Gleitkommatypen auf, wie float
und double
, da sie die speziellen Werte PositiveInfinity
, NegativeInfinity
und NaN
. Alle drei Create*
APIs verhalten sich wie CreateSaturating
. Außerdem stellen MinValue
und MaxValue
die größte negative/positive "normal"-Zahl dar, während die tatsächlichen Mindest- und Höchstwerte NegativeInfinity
und PositiveInfinity
sind, sodass sie stattdessen auf diese Werte begrenzt werden.
Operatorschnittstellen
Die Operatorschnittstellen entsprechen den verschiedenen Operatoren, die für die C#-Sprache verfügbar sind.
- Sie koppeln explizit keine Vorgänge wie Multiplikation und Division, da dies für alle Typen nicht korrekt ist. Beispielsweise
Matrix4x4 * Matrix4x4
ist gültig, aberMatrix4x4 / Matrix4x4
nicht gültig. - Sie ermöglichen es in der Regel, dass Eingabewerte und Ergebnistypen unterschiedlich sein können, um Szenarien zu unterstützen, wie z. B. das Teilen zweier ganzer Zahlen, um einen
double
zu erhalten, oder die Berechnung des Mittelwerts einer Reihe ganzer Zahlen.
Schnittstellenname | Definierte Operatoren |
---|---|
IAdditionOperators<TSelf,TOther,TResult> | x + y |
IBitwiseOperators<TSelf,TOther,TResult> |
x & y , 'x | y', x ^ y und ~x |
IComparisonOperators<TSelf,TOther,TResult> |
x < y , x > y , x <= y und x >= y |
IDecrementOperators<TSelf> |
--x und x-- |
IDivisionOperators<TSelf,TOther,TResult> | x / y |
IEqualityOperators<TSelf,TOther,TResult> |
x == y und x != y |
IIncrementOperators<TSelf> |
++x und x++ |
IModulusOperators<TSelf,TOther,TResult> | x % y |
IMultiplyOperators<TSelf,TOther,TResult> | x * y |
IShiftOperators<TSelf,TOther,TResult> |
x << y und x >> y |
ISubtractionOperators<TSelf,TOther,TResult> | x - y |
IUnaryNegationOperators<TSelf,TResult> | -x |
IUnaryPlusOperators<TSelf,TResult> | +x |
Hinweis
Einige der Schnittstellen definieren neben einem regulären, nicht überprüften Operator auch einen überprüften Operator. Überprüfte Operatoren werden in überprüften Kontexten aufgerufen und ermöglichen es einem benutzerdefinierten Typ, das Überlaufverhalten zu definieren. Wenn Sie einen überprüften Operator (z. B. CheckedSubtraction(TSelf, TOther)) implementieren, müssen Sie auch den nicht überprüften Operator (z. B. Subtraction(TSelf, TOther)) implementieren.
Funktionsschnittstellen
Die Funktionsschnittstellen definieren allgemeine mathematische APIs, die breiter als auf eine bestimmte numerische Schnittstelle angewendet werden. Diese Schnittstellen werden alle von IFloatingPointIeee754<TSelf> implementiert und können in Zukunft von anderen relevanten Typen implementiert werden.
Schnittstellenname | BESCHREIBUNG |
---|---|
IExponentialFunctions<TSelf> | Macht exponentielle Funktionen verfügbar, die e^x , e^x - 1 , 2^x , 2^x - 1 , 10^x und 10^x - 1 unterstützen. |
IHyperbolicFunctions<TSelf> | Macht hyperbolische Funktionen sichtbar, die acosh(x) , asinh(x) , atanh(x) , cosh(x) , sinh(x) und tanh(x) unterstützen. |
ILogarithmicFunctions<TSelf> | Exponiert logarithmische Funktionen, die ln(x) , ln(x + 1) , log2(x) , log2(x + 1) , log10(x) und log10(x + 1) unterstützen. |
IPowerFunctions<TSelf> | Macht Potenzfunktionen verfügbar, die x^y unterstützen. |
IRootFunctions<TSelf> | Macht Stammfunktionen verfügbar, die cbrt(x) und sqrt(x) unterstützen. |
ITrigonometricFunctions<TSelf> | Macht trigonometrische Funktionen verfügbar, die acos(x) , asin(x) , atan(x) , cos(x) , sin(x) und tan(x) unterstützen. |
Analysieren und Formatieren von Schnittstellen
Die Analyse und Formatierung sind Kernkonzepte bei der Programmierung. Sie werden häufig beim Konvertieren von Benutzereingaben in einen bestimmten Typ oder beim Anzeigen eines Typs für den Benutzer verwendet. Diese Schnittstellen befinden sich im System Namespace.
Schnittstellenname | BESCHREIBUNG |
---|---|
IParsable<TSelf> | Macht die Unterstützung von T.Parse(string, IFormatProvider) und T.TryParse(string, IFormatProvider, out TSelf) verfügbar. |
ISpanParsable<TSelf> | Macht die Unterstützung von T.Parse(ReadOnlySpan<char>, IFormatProvider) und T.TryParse(ReadOnlySpan<char>, IFormatProvider, out TSelf) verfügbar. |
IFormattable 1 | Macht die Unterstützung von value.ToString(string, IFormatProvider) verfügbar. |
ISpanFormattable 1 | Macht die Unterstützung von value.TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider) verfügbar. |
1Diese Schnittstelle ist weder neu noch generisch. Es wird jedoch von allen Zahlentypen implementiert und stellt die umgekehrte Operation von IParsable
dar.
Das folgende Programm verwendet beispielsweise zwei Zahlen als Eingabe und liest sie mithilfe einer generischen Methode, bei der der Typparameter auf IParsable<TSelf> beschränkt ist, aus der Konsole. Er berechnet den Mittelwert mithilfe einer generischen Methode, bei der die Typparameter für die Eingabe- und Ergebniswerte eingeschränkt sind INumber<TSelf>, und zeigt dann das Ergebnis der Konsole an.
using System.Globalization;
using System.Numerics;
static TResult Average<T, TResult>(T first, T second)
where T : INumber<T>
where TResult : INumber<TResult>
{
return TResult.CreateChecked( (first + second) / T.CreateChecked(2) );
}
static T ParseInvariant<T>(string s)
where T : IParsable<T>
{
return T.Parse(s, CultureInfo.InvariantCulture);
}
Console.Write("First number: ");
var left = ParseInvariant<float>(Console.ReadLine());
Console.Write("Second number: ");
var right = ParseInvariant<float>(Console.ReadLine());
Console.WriteLine($"Result: {Average<float, float>(left, right)}");
/* This code displays output similar to:
First number: 5.0
Second number: 6
Result: 5.5
*/