Wie meinst du das? Die aufrufende Methode soll nur diese Werte hereingeben oder soll die Methode ProcessValues nur Parameter in diesem Wertebereich annehmen. Was soll passieren, wenn die Werte nicht in dem Bereich liegen?
Ab .NET 4 gibt es eingebaute Unterstützung für "Design by Contract" in Gestalt der Contract-Klasse. Damit könntest Du am Anfang Deiner Methode schreiben
private string ProcessValues(int i, int j) { Contract.Requires(1 < i && i < 100); ... }
Nicht so tief im Framework verankert, dafür auch in älteren Version nutzbar, ist CuttingEdge.Conditions.
Im Sinne von Zorros Rückfrage wäre das eine Lösung, die sicherstellt, dass die Methode nur Werte aus dem vorgegebenen Bereich annimmt. Mit Datentypen, wie sie Jürgen vorgeschlagen hat, zwingst Du hingegen den Aufrufer, in seinem Verantwortungsbereich für die Einhaltung des Wertebereichs zu sorgen und kannst dann in Deiner Methode sicher sein, dass nichts anderes hereinkommt. Das ist aber nur dann ein gangbarer Weg, wenn es Dir nur um wenige feste Wertebereiche geht, die möglichst auch eine fachliche Bedeutung haben sollten, z.B. "Lottozahlen" anstelle von "Range1To49".
Hier ein Beispiel Ohne Attribute, das zur Laufzeit den Wertebereich prüft (von der Syntax ähnlich Contract, aber eben zur Laufzeit):
private int _rangedIntProperty;
/// <summary> Min = 5, Max = 10 </summary> public int RangedIntProperty { get { return _rangedIntProperty; } set { Util.VerifyRange(value, 5, 10); _rangedIntProperty = value; } }
public static void VerifyRange(int val, int min, int max) { if (val < min || val > max) throw new ArgumentOutOfRangeException("Value " + val + " was out of the allowed range (" + min + ", " + max + ")"); }
Der implicit-Operator sollte aber nur für die Konvertierung eigener Typ -> int verwendet werden, in der Gegenrichtung ist eine explizite Konvertierung vorzuziehen.
Du könntest ein eigenes Attribute definieren welches diese Aufgabe für dich übernimmt. Der Sprachsyntax von C# unterstützt es jedoch nicht von haus aus.
Meine Empfehlung wäre eine ArgumentOutOfRangeException zu werfen, entweder in der Methode oder eben über eine eigene Klasse.
public struct ValueProcessor { public ValueProcessor(int i, int j) { if (i < 1 && i > 10) throw new ArgumentOutOfRangeException("i"); if (j < 400 && j > 500) throw new ArgumentOutOfRangeException("j");
I = i; J = j; }
public int I { get; set; } public int J { get; set; } }
// Method signature public string ProcessValues(ValueProcessor processor);
Der Vorteil dieser Methode wäre auch, dass du verschiedene Klassen für verschiedene Wertebereiche erstellen kannst.
Was natürlich noch möglich wäre, aber etwas undurchschaubarer ist, dass du zum Beispiel statt der ArgumentOutOfRangeException den Wert auf das Minimum bzw. das Maximum setzt.
Soweit ich sehe, muss der Konstruktor den Standardkonstruktor aufrufen, damit der Code überhaupt kompiliert. Und da sich bei structs der Standardkonstruktor nicht ausblenden läßt, braucht man passende Default-Werte für I und J, sonst wird ProcessValues am Ende doch mit (0,0) aufgerufen. Aber ob sich fachlich sinnvolle Default-Werte überhaupt festlegen lassen, ist nicht von vornherein klar.