12 Stimmen

Nullbarer generischer Typ, der mit IComparable verwendet wird. Ist das möglich?

Ich versuche, eine einfache Klammer zu erstellen (so dass ich die Werte von etwas Vergleichbarem begrenzen kann ... vor allem für Zahlentypen wie int, double, usw.)

Das Problem ist, wenn ich das Folgende tue, erhalte ich einen Fehler, aber laut MSDN IComparable's CompareTo soll mit Nullwerten umgehen können.
Zitat: "Per Definition wird jedes Objekt größer als Null verglichen, und zwei Null-Referenzen werden gleich verglichen."

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

    if (value.CompareTo(min) < 0)
        return min;

    return value;
}

private Int32? _zip;
public Int32? Zip
{
    get
    {
        return _zip;
    }
    set
    {
        _zip = value.Clamp<Int32?>(0, 99999);
    }
}

16voto

Iñaki Elcoro Punkte 2125

Wie von @LBushkin gesagt, implementiert Nullable< T > oder T? nicht die Schnittstelle IComparable. Die angegebene Lösung ist in Ordnung, allerdings ziehe ich es vor, die Nullable-Vergleichslogik innerhalb einer spezialisierten Klasse zu haben, die dem Prinzip der einzigen Verantwortung und kann auch zum Vergleich beliebiger nullbarer Typen verwendet werden.

Sie könnten zum Beispiel eine generische Nullable-Typ-Vergleichsklasse wie diese erstellen:

public class NullableComparer<T> : IComparer<Nullable<T>>
      where T : struct, IComparable<T>
{

     public int Compare(Nullable<T> x, Nullable<T> y)
     {
        //Compare nulls acording MSDN specification

        //Two nulls are equal
        if (!x.HasValue && !y.HasValue)
            return 0;

        //Any object is greater than null
        if (x.HasValue && !y.HasValue) 
            return 1;

        if (y.HasValue && !x.HasValue)
            return -1;

        //Otherwise compare the two values
        return x.Value.CompareTo(y.Value);
     }

}

In diesem Fall würden Sie diese Klasse wie folgt verwenden:

public static T? Clamp<T>(this T? value, T? min, T? max)
    where T : struct
{
    var comparer = new NullableComparer<T>();

    if (comparer.Compare(value, max) > 0)
        return max;

    if (comparer.Compare(value, min) < 0)
        return min;

    return value;
}

Praktisch zum Speichern in der Bibliothek Ihrer Helfer.

Hoffentlich hilft das!

7voto

LBushkin Punkte 124894

Erinnern Sie sich, Int32? ist eine Abkürzung für Nullable<Int32> . Desde Nullable<T> implementiert nicht IComparable<T> wird Ihr Code, so wie er strukturiert ist, nicht kompiliert.

Sie können die Methode jedoch überladen:

public static T? Clamp<T>(this T? value, T? min, T? max) 
    where T : struct, IComparable<T> 
{ 
    // your logic...
} 

Wenn Sie planen, mit nullbaren Typen zu arbeiten, müssen Sie natürlich definieren, wie Sie die null Werte...

Wenn Sie nicht unbedingt klemmen müssen null Werte, kann es einfacher sein, zunächst nur auf null in Ihrem Property Getter zu prüfen:

public Int32? Zip
{
   ...
   set
   {
       _zip = value == null ? value : value.Value.Clamp<Int32>(0,99999);
   }

Oder besser noch, machen Sie es zu einem Teil der Implementierung der zusätzlichen Überladung von Clamp ...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X