2015-04-29 5 views
8

Ich habe eine Struktur bekommt:Welche impliziten Konvertierungen werden unterstützt, wenn < and > Operatoren verwendet werden?

public struct Decibel 
{ 
    public readonly double Value; 

    public Decibel (double value) 
    { 
     Value = value; 
    } 

    public static implicit operator Decibel (double decibels) 
    { 
     return new Decibel (decibels); 
    } 

    public static implicit operator double (Decibel decibels) 
    { 
     return decibels.Value; 
    } 
} 

Und jetzt kann ich tun:

bool x = new Decibel (0) < new Decibel (1); 

Es scheint, der Compiler ist intelligent genug, -double, zu konvertieren und dann den < Operator für das Doppel benutzen?

Ich hatte verschiedene struct namens Duration, die TimeSpan war. Es hatte implizite Konvertierungen für TimeSpan zu/von Duration, aber die < und > Operatoren funktionieren nicht dafür.

Erkennt C# nur die Konvertierung zwischen primitiven Typen?

+0

Es relevante Informationen von Eric Lippert ist hier: http://stackoverflow.com/a/8529811/106159 –

+0

'implicit' Umwandlungen machen es sehr einfach sich in den Fuß schießen. Sie sollten nur selten und sorgfältig verwendet werden. Und eine implizite Umwandlung in einen primitiven Typ ist nur eine schlechte Idee. –

+0

@HenkHolterman: Ich weiß, ich versuche es vorsichtig zu verwenden :) – zgnilec

Antwort

3

Beachten Sie zuerst, dass C# maximal eine implizite benutzerdefinierte Konvertierung zwischen Typen erlaubt.

Also, wenn Sie zwei Instanzen von vergleichen zu können, sieht der Compiler, dass es eine benutzerdefinierte implizite Konvertierung ein zu einem double mit dem umwandeln können zu vergleichen.

Wenn Sie jedoch zwei Instanzen von Duration vergleichen, kann der Compiler keine einfache implizite Konvertierung finden, die es verwenden kann, um den Vergleich zu ermöglichen. Der Compiler berücksichtigt keine benutzerdefinierten Vergleichsoperatoren für die Typen, auf die der Typ implizit konvertiert werden kann. Es sucht nur nach integrierten Vergleichsoperatoren für die Typen, auf die der Typ implizit konvertiert werden kann.

Daher wird der Compiler nicht die implizite Konvertierung zu TimeSpan verwenden, obwohl TimeSpan einen benutzerdefinierten Vergleichsoperator bietet, der theoretisch verwendet werden könnte.

Auch wenn die TimeSpan Klasse eine implizite Konvertierung zu double lieferte, würde der Compiler sie immer noch nicht verwenden, da sie höchstens eine implizite benutzerdefinierte Konvertierung in der Kette der impliziten Konvertierungen berücksichtigt.

Mit anderen Worten, da diese Strukturen:

public struct Number 
{ 
    public readonly double Value; 

    public Number(double value) 
    { 
     Value = value; 
    } 

    public static implicit operator Number(double duration) 
    { 
     return new Number(duration); 
    } 

    public static implicit operator double(Number number) 
    { 
     return number.Value; 
    } 
} 

public struct NumberWrapper 
{ 
    public readonly Number Value; 

    public NumberWrapper(Number value) 
    { 
     Value = value; 
    } 

    public static implicit operator NumberWrapper(Number duration) 
    { 
     return new NumberWrapper(duration); 
    } 

    public static implicit operator Number(NumberWrapper number) 
    { 
     return number.Value; 
    } 
} 

Dieser Code kompiliert:

bool x = new Number(1) < new Number(2); 

Und so natürlich wird dies:

Number n1 = new NumberWrapper(1); 
Number n2 = new NumberWrapper(2); 
bool z = n1 < n2; 

aber dies wird nicht :

bool y = new NumberWrapper(1) < new NumberWrapper(2); 

weil NumberWrapper keine implizite Konvertierung in einen beliebigen Typ hat, der < ohne weitere implizite Konvertierungen unterstützt.

Beachten Sie, dass alle primitiven numerischen Typen und Aufzählungstypen (z. B. char, short, int, long, float, double, decimal, enum) integrierte Vergleichsoperatoren bereitstellen. Alle anderen Typen können nur benutzerdefinierte Vergleichsoperatoren bereitstellen.

Benutzerdefinierte Vergleichsoperatoren wie folgt aussehen:

public static bool operator < (MyType lhs, MyType rhs) ... 
+0

Vielleicht sollten Sie den Unterschied zwischen "benutzerdefinierten Vergleichsoperatoren" und "eingebauten Vergleichsoperatoren" erklären, nur um es klarer zu machen. – Magnus

+0

@Magnus: Ja, sind Operator für TimeSpan Build Int? Oder sind eingebaute Operatoren für primitive Typen? – zgnilec

+0

@zgnilec Die Operatoren sind nur für primitive Typen eingebaut (wie ich am Ende meiner Antwort geschrieben habe) –