web-dev-qa-db-ja.com

数値をC#の範囲に強制するにはどうすればよいですか?

C#では、多くの場合、整数値を値の範囲に制限する必要があります。たとえば、アプリケーションがパーセンテージを想定している場合、ユーザー入力の整数は0未満または100を超えてはなりません。別の例:_Request.Params["p"]_を介してアクセスされる5つのWebページがある場合、0または256または99999ではなく、1〜5の値が必要です。

私はしばしば次のような非常にいコードを書くことで終わります:

_page = Math.Max(0, Math.Min(2, page));
_

またはさらにい:

_percentage =
    (inputPercentage < 0 || inputPercentage > 100) ?
    0 :
    inputPercentage;
_

.NET Framework内でこのようなことを行うスマートな方法はありませんか?

一般的なメソッドint LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum)を記述してすべてのプロジェクトで使用できることは知っていますが、フレームワークにはすでに魔法のメソッドがありますか?

手動で実行する必要がある場合、最初の例で実行していることを実行するための「最良の」(つまり、よりくなく、より高速な)方法は何でしょうか。このようなもの?

_public int LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum)
{
    if (value >= inclusiveMinimum)
    {
        if (value <= inlusiveMaximum)
        {
            return value;
        }

        return inlusiveMaximum;
    }

    return inclusiveMinimum;
}
_
29

マークの答えを見て、thisでそれを上げます:

public static class InputExtensions
{
    public static int LimitToRange(
        this int value, int inclusiveMinimum, int inclusiveMaximum)
    {
        if (value < inclusiveMinimum) { return inclusiveMinimum; }
        if (value > inclusiveMaximum) { return inclusiveMaximum; }
        return value;
    }
}

使用法:

int userInput = ...;

int result = userInput.LimitToRange(1, 5)

参照: 拡張メソッド

27
dtb

この操作は「クランプ」と呼ばれ、通常次のように記述されます。

public static int Clamp( int value, int min, int max )
{
    return (value < min) ? min : (value > max) ? max : value;
}
56
Trap

単なる整数以上のもので動作するはるかにきれいなメソッド(共有コードの私自身のライブラリから取得):

public static T Clamp<T>(T value, T min, T max) where T : IComparable<T>
{
    if (value.CompareTo(min) < 0)
        return min;
    if (value.CompareTo(max) > 0)
        return max;

    return value;
}
26
MikeP

LimitToRange関数を記述する別の方法は次のとおりです。

public int LimitToRange(int value, int inclusiveMinimum, int inclusiveMaximum)
{
    if (value < inclusiveMinimum) { return inclusiveMinimum; }
    if (value > inclusiveMaximum) { return inclusiveMaximum; }
    return value;
}

これはまだ効率的でありながら理解しやすいと思います。

7
Mark Byers

Guffaの答えは気に入っていますが、Min/Maxを使用したソリューションを誰もまだ投稿していないことに驚いています。

public int LimitInclusive(int value, int min, int max)
{
    return Math.Min(max, Math.Max(value, min));
}
7
Ed S.

一般に、ユーザーが入力した値が間違っているというフィードバックをユーザーに提供せずに値をクランプすることは、素晴らしいアイデアではないかもしれません(IMHO)。これにより、後で実行時に最小/最大値が決定される場合、デバッグが困難な微妙なバグが発生する可能性があります。

これを考えてください。銀行口座に100ドルがあり、友人に150ドルを送金したいとします。銀行システムでInsufficientFundsExceptionをスローするか、友人と話し合って、150ドルを送金したが、彼は100ドルしか受け取っていないことを望みますか(十分な資金がないため、銀行が振替額を100に固定したと仮定)

とはいえ、コードコントラクトも確認する必要があります。

public void MyFunction (Type input)
{
   Contract.Requires(input > SomeReferenceValue);
   Contract.Requires (input < SomeOtherReferencValue);

}

これにより、ユーザー入力が強制的に範囲内になります。

3
ram

いいえ、フレームワークに組み込まれているメソッドはありません。既にMinMaxが存在するため、除外されたと思われます。

独自のメソッドを記述する場合、どのように記述するかは重要ではありません。 ifステートメントまたは条件演算子?を使用する場合、とにかくほとんど同じコードにコンパイルされます。

3
Guffa

クランプ名が好きです。私は次のクラスを提案します

public class MathHelper
{
    public static int Clamp (int value,int min,int max)
    {
          // todo - implementation 
    }
    public static float Clamp (float value,float min,float max)
    {
          // todo - implementation 
    }
)

またはジェネリックを使用する場合は、

public class MathHelper
{
     public static T Clamp<T> (T value, T min, T max) where T : IComparable
     {
         // todo - implementation
         T output = value;
         if (value.CompareTo(max) > 0)
         {
             return max;
         }
         if (value.CompareTo(min) < 0)
         {
            return min;
         }
        return  output;
     } 
}
1
Syd