Frage

Update!

Meine Präparation eines Teils der C # spec unten; Ich glaube, ich muss etwas, weil auf fehlt mir es sieht aus wie das Verhalten, das ich in dieser Frage zu beschreiben bin verletzt tatsächlich die spec.

Update 2!

OK, auf weitere Überlegungen und basierend auf einigen Kommentaren, ich glaube, ich verstehe jetzt, was los ist. Die Worte „Quelltyp“ in der zu dem Typ ist, beziehen sich spec konvertiert aus - dh Type2 in meinem Beispiel unten - was einfach bedeutet, dass der Compiler in der Lage ist, die Kandidaten bis auf die beiden zu verengen definierten Operatoren (da Type2 ist der Quelltyp für beide). Er kann jedoch nicht die Entscheidungen, jede weitere verengen. So die Schlüsselwörter in der Spezifikation (wie es auf diese Frage gilt) ist „Quelltyp“ , die ich vorher falsch interpretiert (glaube ich) bedeuten „Typen zu deklarieren.“


Original Frage

sagen, ich habe diese Typen definiert:

class Type0
{
    public string Value { get; private set; }

    public Type0(string value)
    {
        Value = value;
    }
}

class Type1 : Type0
{
    public Type1(string value) : base(value) { }

    public static implicit operator Type1(Type2 other)
    {
        return new Type1("Converted using Type1's operator.");
    }
}

class Type2 : Type0
{
    public Type2(string value) : base(value) { }

    public static implicit operator Type1(Type2 other)
    {
        return new Type1("Converted using Type2's operator.");
    }
}

Dann sage ich dies tun:

Type2 t2 = new Type2("B");
Type1 t1 = t2;

Natürlich ist dies nicht eindeutig, da es nicht klar ist, welche implicit Operator verwendet werden soll. Meine Frage ist - da kann ich nicht sehen jede Möglichkeit, diese Mehrdeutigkeit aufzulösen (es ist nicht wie ich ist eine explizite Umwandlung durchführen kann, zu klären, welche Version ich will), und doch sind die Klassendefinitionen oben Kompilierung tun - warum sollte der Compiler diese passende implicit Operatoren überhaupt zulassen


Dissection

OK, ich bin durch den Auszug aus dem C # spec von Hans Passant in einem Versuch, zitierte Schritt gehe Sinn daraus zu machen.

  

Finden Sie den Satz von Typen, D, von denen   benutzerdefinierte Konvertierungsoperatoren werden   in Betracht gezogen werden. Dieses Set besteht aus S   (Wenn S eine Klasse oder Struktur ist), wobei die Basis   Klassen von S (wenn S ist eine Klasse) und T   (Wenn T eine Klasse oder Struktur).

Wir konvertieren von Type2 ( S ) Type1 ( T ). So scheint es, dass hier D würde alle drei Typen im Beispiel: Type0, Type1 ( (weil es sich um eine Basisklasse von S ist) T ) und Type2 ( S ).

  

Hier finden Sie die Menge der anwendbaren   benutzerdefinierte Umwandlungsoperator, U.   Dieses Set besteht aus dem benutzerdefinierten   implizite Konvertierung Betreiber erklärt   von den Klassen oder Strukturen in D, dass   Umwandlung von einem Typ umfassend S   eine Art von T. Wenn U umfasst ist   leer, die Umwandlung ist nicht definiert und   ein Fehler bei der Kompilierung auftritt.

In Ordnung, haben wir zwei Operatoren diese Bedingungen erfüllt bekommen. Die Version erklärt in Type1 die Anforderungen erfüllt, weil Type1 in ist D und wandelt es von Type2 (was offensichtlich umgreift S ) zu Type1 (die offensichtlich von T umgeben ist ). Die Version in Type2 auch erfüllt die Anforderungen an genau den gleichen Gründen. So U enthält sowohl diese Operatoren.

Schließlich mit Bezug auf das Finden der speziellsten "Quelltyp" SX der Betreiber in U :

  

Wenn einer der Operatoren in U convert von S, dann SX ist S.

beide Betreiber in U convert von S - so das sagt mir, dass SX ist < strong> S .

nicht über diese bedeuten, dass die Type2 Version verwendet werden soll?

Aber Wartezeit! Ich bin verwirrt!

Könnte ich nicht haben nur definiert Type1 Version des Betreibers, wobei in diesem Fall die einzige verbleibende Kandidat Type1 Version sein würde und nach noch zu spec SX würde Type2 sein? Dies scheint ein mögliches Szenario, in dem die spec Mandaten etwas unmöglich ist (nämlich, dass die Umwandlung in Type2 erklärt soll verwendet werden, wenn in der Tat es ist nicht vorhanden).

War es hilfreich?

Lösung

Wir wollen es nicht wirklich ein Fehler bei der Kompilierung wird nur Conversions zu definieren, die Macht Ursache Mehrdeutigkeit. Nehmen wir an, wir Type0 ändern, um eine Doppel zu speichern, und aus irgendeinem Grund wollen wir getrennte Conversions Signed Integer und unsigned integer liefern.

class Type0
{
    public double Value { get; private set; }

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

    public static implicit operator Int32(Type0 other)
    {
        return (Int32)other.Value;
    }

    public static implicit operator UInt32(Type0 other)
    {
        return (UInt32)Math.Abs(other.Value);
    }

}

Dieses compiliert in Ordnung, und ich kann Gebrauch beiden Umwandlungen mit

verwenden
Type0 t = new Type0(0.9);
int i = t;
UInt32 u = t;

Es ist jedoch ein Compiler-Fehler versuchen float f = t, weil entweder die impliziten Konvertierungen verwendet werden könnte, um einen Integer-Typen zu erhalten, die dann in float umgewandelt werden kann.

Wir wollen nur der Compiler über diese komplexere Mehrdeutigkeiten beschweren, wenn sie tatsächlich gewohnt sind, da wir die Type0 oben zu kompilieren möchten. Aus Gründen der Einheitlichkeit führen die einfachere Zweideutigkeit sollte auch einen Fehler an dem Punkt Sie es verwenden, anstatt, wenn Sie es definieren.

Bearbeiten

Da Hans seine Antwort entfernt, die die Spezifikation zitiert, hier ist ein kurzer Überblick über den Teil des C # spec, der bestimmt, ob eine Konvertierung mehrdeutig ist, mit definiert U die Menge aller Konvertierungen zu sein, die möglicherweise die Arbeit machen könnten:

  
      
  • Finden Sie die spezifische Quelle Typ, SX, der Operatoren in U:      
        
    • Wenn einer der Operatoren in U convert von S, dann SX ist S.
    •   
    • Ansonsten SX die meisten umfasste Typ in der kombinierten Gruppe von Zielarten der Operatoren in U. Wenn kein meisten umfasste Typ gefunden werden kann, dann ist die Umwandlung ist nicht eindeutig und ein Fehler bei der Kompilierung auftritt.
    •   
  •   

paraphrasiert bevorzugen wir eine Umwandlung, die direkt von S umwandelt, ansonsten wir die Art bevorzugen, die „einfachste“ ist zu konvertieren S zu. In beiden Beispielen haben wir zwei Konvertierungen von S zur Verfügung. Wenn es von Type2 keine Wandlungen waren, würden wir eine Umwandlung von Type0 über ein von object bevorzugen. Wenn niemand Art von offensichtlich die bessere Wahl zu konvertieren ist, scheitern wir hier.

  
      
  • Finden Sie den spezifischen Zieltyp, TX, der Operatoren in U:      
        
    • Wenn einer der Operatoren in U Konvertit T, dann TX ist T.
    •   
    • Ansonsten TX ist die umfassendste Typ in der kombinierten Gruppe von Zielarten der Operatoren in U. Wenn kein meisten Typ umfasst gefunden werden kann, dann ist die Umwandlung ist nicht eindeutig und ein Fehler bei der Kompilierung auftritt.
    •   
  •   

Auch hier würden wir direkt an T konvertieren bevorzugen, aber wir werden für die Art regeln, die „einfachste“ zu konvertieren T. In Dans Beispiel ist, haben wir zwei Conversions T zur Verfügung. In meinem Beispiel sind die möglichen Ziele Int32 und UInt32, und keiner ist ein besseres Spiel als die anderen, so ist dies, wo die Konvertierung fehlschlägt. Der Compiler hat keine Möglichkeit, zu wissen, ob float f = t Mittel float f = (float)(Int32)t oder float f = (float)(UInt32)t.

  
      
  • Falls U enthält genau einen benutzerdefinierten Umwandlungsoperator dass wandelt von SX zu TX, dann ist dies der spezifische Konvertierungsoperator. Wenn kein solcher Betreiber vorhanden ist, oder wenn mehr als ein solcher Betreiber vorhanden ist, dann ist die Umwandlung ist nicht eindeutig und ein Fehler bei der Kompilierung auftritt.
  •   

In Dans Beispiel scheitern wir hier, weil wir zwei Conversions links von SX TX. Wir konnten keine Konvertierungen von SX TX haben, wenn wir verschiedene Konvertierungen gewählt haben, als SX und TX entscheiden. Zum Beispiel, wenn wir ein Type1a von Type1 abgeleitet haben, dann könnten wir Konvertierungen von Type2 zu Type1a und von Type0 diese Type1 würde wir noch SX = Typ2 und TX = Typ1 geben, aber wir haben eigentlich keine Umwandlung von Typ2 zu Typ1. Das ist in Ordnung, weil das ist wirklich nicht eindeutig ist. Der Compiler weiß nicht, ob Typ2 zu Type1a konvertieren und dann zu Typ1 gegossen oder gegossen zu Type0 zunächst so, dass es die Umstellung auf Typ1 verwenden kann.

Andere Tipps

Schließlich kann es nicht mit vollem Erfolg prohibitted werden. Sie und ich konnte zwei Baugruppen veröffentlichen. Sie konnten wir beginnen jeweils anderen zusammenbaut verwenden, während unsere eigene zu aktualisieren. Dann könnten wir liefern jeweils implizite Abgüsse zwischen Typen in jeder Baugruppe definiert. Nur wenn wir die nächste Version veröffentlichen, könnte dies gefangen werden, anstatt bei der Kompilierung.

Es ist ein Vorteil in nicht versuchen, Dinge zu verbieten, die nicht verboten werden kann, wie es aus Gründen der Klarheit und Konsistenz macht (und es ist eine Lektion für die Gesetzgeber, dass).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top