Wo finde ich die „Klemme“ Funktion in .NET finden?
Frage
Ich möchte einen Wert x
auf einen Bereich [a, b]
einzuspannen:
x = (x < a) ? a : ((x > b) ? b : x);
Das ist ganz einfach. Aber ich habe keine Funktion „Klammer“ in der Klassenbibliothek sehen -. Zumindest nicht in System.Math
(Für die nicht bewusst zu „Klemme“ ein Wert, um sicherzustellen, ist, dass es zwischen einigen Maximal- und Minimalwerten liegt. Wenn es größer ist als der Maximalwert, dann wird es durch den max ersetzt, usw.)
Lösung
Sie können eine Erweiterungsmethode schreiben:
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0) return min;
else if(val.CompareTo(max) > 0) return max;
else return val;
}
EDIT: Erweiterungsmethoden gehen in statischen Klassen - da dies durchaus eine Low-Level-Funktion, ist es wahrscheinlich in einigen Kernnamespace in Ihrem Projekt gehen. Anschließend können Sie das Verfahren in jeder Codedatei verwenden, die eine using-Direktive für den Namespace z enthält.
using Core.ExtensionMethods
int i = 4.Clamp(1, 3);
.NET Core 2.0
Beginnend mit .NET Core 2.0 System.Math
hat jetzt ein Clamp
Methode, die stattdessen verwendet werden kann:
using System;
int i = Math.Clamp(4, 1, 3);
Andere Tipps
Versuchen Sie:
public static int Clamp(int value, int min, int max)
{
return (value < min) ? min : (value > max) ? max : value;
}
Just Verwendung Math.Min
und Math.Max
:
x = Math.Min(Math.Max(x, a), b);
Es gibt nicht ein, aber es ist nicht allzu schwer zu machen. Ich fand man hier: Klemme
Es ist:
public static T Clamp<T>(T value, T max, T min)
where T : System.IComparable<T> {
T result = value;
if (value.CompareTo(max) > 0)
result = max;
if (value.CompareTo(min) < 0)
result = min;
return result;
}
Und es kann wie verwendet werden:
int i = Clamp(12, 10, 0); -> i == 10
double d = Clamp(4.5, 10.0, 0.0); -> d == 4.5
Es gibt nicht einen im System.Math Namespace
http://msdn.microsoft.com/en-us/ Bibliothek / system.math_members.aspx
Es gibt eine MathHelper Klasse, wo es für XNA Game Studio zur Verfügung, wenn das passiert zu sein, was Sie tun:
http://msdn.microsoft.com /en-us/library/bb197892(v=XNAGameStudio.31).aspx
Just teilen Lees Lösung mit den Kommentaren der Fragen und Bedenken, soweit möglich:
public static T Clamped<T>(this T value, T min, T max) where T : IComparable<T> {
if (value == null) throw new ArgumentNullException(nameof(value), "is null.");
if (min == null) throw new ArgumentNullException(nameof(min), "is null.");
if (max == null) throw new ArgumentNullException(nameof(max), "is null.");
//If min <= max, clamp
if (min.CompareTo(max) <= 0) return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value;
//If min > max, clamp on swapped min and max
return value.CompareTo(max) < 0 ? max : value.CompareTo(min) > 0 ? min : value;
}
Unterschiede:
- Methodenname verwendet die entsprechende Verbform (
ed
) bis (weiter) zeigt, dass der Wert nicht an Ort und Stelle eingespannt ist, und dass stattdessen ein neuer Wert zurückgegeben wird (siehe @ JimBalter Kommentar ). - Ist entsprechenden
null check
auf allen Eingängen (Siehe @ JeppeStigNielsen Kommentar ). - Swaps
min
undmax
wennmin > max
(Siehe @ JeppeStigNielsen Kommentar ).
Einschränkungen:
Keine einseitigen Klammern. Wenn max
NaN
ist, kehrt immer wieder NaN
(Siehe Hermans Kommentar ).
die bisherigen Antworten benutzen, ich kondensiert es für meine Bedürfnisse Code unten auf die nach unten. Dies erlaubt es Ihnen auch durch seine min oder max eine Zahl nur zu klemmen.
public static class IComparableExtensions
{
public static T Clamped<T>(this T value, T min, T max)
where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min : value.ClampedMaximum(max);
}
public static T ClampedMinimum<T>(this T value, T min)
where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min : value;
}
public static T ClampedMaximum<T>(this T value, T max)
where T : IComparable<T>
{
return value.CompareTo(max) > 0 ? max : value;
}
}
Die folgenden Code unterstützt Grenzen in beliebiger Reihenfolge (d.h. bound1 <= bound2
oder bound2 <= bound1
) angibt. Ich habe diese nützlich gefunden für Werte berechnet aus linearen Gleichungen (y=mx+b
), wo die Steigung der Linie Klemm kann zu- oder abnimmt.
Ich weiß: Der Code besteht aus fünf Super-hässlich bedingten Ausdruck Operatoren . Die Sache ist, es funktioniert , und die Tests unten beweisen. Fühlen Sie sich frei hinzuzufügen streng unnötige Klammern, wenn Sie dies wünschen.
Sie können ganz einfach andere Überlastungen für andere numerische Typen erstellen und im Grunde Kopieren / Einfügen der Tests.
Achtung: Beim Vergleich Gleitkommazahlen ist nicht einfach. Dieser Code implementiert nicht double
Vergleiche robust. Verwenden Sie eine Gleitkomma-Vergleich Bibliothek, um die Verwendung von Vergleichsoperatoren zu ersetzen.
public static class MathExtensions
{
public static double Clamp(this double value, double bound1, double bound2)
{
return bound1 <= bound2 ? value <= bound1 ? bound1 : value >= bound2 ? bound2 : value : value <= bound2 ? bound2 : value >= bound1 ? bound1 : value;
}
}
xUnit / FluentAssertions Tests:
public class MathExtensionsTests
{
[Theory]
[InlineData(0, 0, 0, 0)]
[InlineData(0, 0, 2, 0)]
[InlineData(-1, 0, 2, 0)]
[InlineData(1, 0, 2, 1)]
[InlineData(2, 0, 2, 2)]
[InlineData(3, 0, 2, 2)]
[InlineData(0, 2, 0, 0)]
[InlineData(-1, 2, 0, 0)]
[InlineData(1, 2, 0, 1)]
[InlineData(2, 2, 0, 2)]
[InlineData(3, 2, 0, 2)]
public void MustClamp(double value, double bound1, double bound2, double expectedValue)
{
value.Clamp(bound1, bound2).Should().Be(expectedValue);
}
}