2014-09-12 13 views
7

Gibt es eine Möglichkeit, kovariante Überschreibungen in C# zu "hacken" oder "zu erzwingen"?Problemumgehung für fehlende Kovarianz vom Rückgabetyp beim Überschreiben virtueller Methoden

Zum Beispiel:

public class Alpha { 
    public virtual Alpha DoSomething() { 
     return AlphaFactory.GetAlphaFromSomewhere(); 
    } 
} 
public class Beta : Alpha { 
    public override Beta DoSomething() { 
     return BetaFactory.GetBetaFromSomewhere(); 
    } 
} 

Leider ist C# nicht unterstützt (was ein bisschen lächerlich scheint, aber das ist weder hier noch dort).

Ich dachte, ich könnte eine Antwort mit der Methode versteckt habe:

new public Beta DoSomething() { 
    return BetaFactory.GetBetaFromSomewhere(); 
} 

Aber nicht fügen Sie den Eintrag in der ‚V-Tabelle‘, es im Grunde nur eine völlig neue Methode mit dem gleichen Namen erklärt, und als solches bedeutet, dass der Zugriff auf Beta s über einen Zeiger auf AlphaAlpha.DoSomething() aufrufen wird.

Also, irgendwelche guten Tricks?

+2

Warum müssen Sie den Rückgabewert ändern? Was erfüllt Ihre Bedürfnisse nicht, wenn 'Beta.DoSomething()' ein 'Alpha'-getipptes Objekt zurückgibt? Solange die richtigen Methoden als virtuell in 'Alpha' definiert und dann in' Beta' überschrieben werden, ist es nicht wirklich wichtig; Jeder Aufruf einer virtuellen Methode wird in den Laufzeittyp des Objekts aufgelöst, nicht in den Kompilierungszeittyp. – InBetween

+0

Wird nicht genug von einem "Hack" geworfen? – Mephy

Antwort

3

Sie können einige ziemlich verrückte Sachen mit Generika machen.

public class Alpha<T> where T: Alpha<T> { 
    public virtual T DoSomething() { 
     throw new NotImplementedException(); 
    } 
} 
public class Beta : Alpha<Beta> { 
    public override Beta DoSomething() { 
     throw new NotImplementedException(); 
    } 
} 
+0

Ein generischer Missbrauch, um genau was zu gewinnen? – InBetween

+0

Wenn Sie einen statischen Verweis auf "Beta" haben, müssen Sie keine Laufzeitumwandlung durchführen, um eine 'Beta'-Referenz von' DoSomething' zu bekommen. – recursive

+0

Oh, so dass Sie das ganze Typsystem mit diesem generischen Kopfschmerz verkomplizieren, um einfach den billigsten möglichen Guss zu vermeiden (auch sicher)? – InBetween

0

Weil es in den meisten Fällen keinen großen Vorteil bei der Rückgabetyp-Kovarianz gibt.

Wenn Sie virtuell anrufen Alpha.DoSomething, dann wissen Sie wirklich nicht, ob Sie eine Alpha oder Beta zurück erhalten, also wie hilft Rückgabetyp Kovarianz? Sie müssen das Ergebnis trotzdem in einem Alpha getippten Objekt speichern, da es der einzige Typ ist, der Alpha s oder Beta s zulassen kann.

Auf der anderen Seite, wenn Sie statisch wissen , die Sie anrufen Beta.DoSomething dann können Sie entweder direkt die zurück Alpha typisierte Objekt verwenden, da Sie Methoden gemeinsame Funktionalität oder virtuellen Zugriff werden, so dass Sie kümmern sich nicht, wenn es wirklich ein Beta (der virtuelle Anruf wird auf den richtigen Typ auflösen) oder Sie können direkt wählen (Runtime Safe) Cast Beta, um auf bestimmte Implementierung zugreifen.

Bearbeiten: das Typsicherheits-Problem wurde entfernt. Ich dachte kaum darüber nach und offenbar würde die Art der Kovarianz sicher sein. Der Rest der Antwort steht jedoch. Ich kann nichts Interessantes in diesem Feature finden, zumindest nicht in der Art, wie das OP es benutzen will: Vermeiden Sie einen sicheren, billigen Cast?

+0

Java kann dies out-of-the-box tun (Sie können den Rückgabetyp von nicht-finalen Methoden in Unterklassen ändern, solange der Rückgabetyp eine Unterklasse des Rückgabetyps in der Basisklasse ist). Ich denke, dass die freudige Entlassung der Bedenken des OP als "kein großer Vorteil" etwas abwegig ist. –

+1

@KirkWoll [Alle C# -Features beginnen mit -100 Punkten] (http://blogs.msdn.com/b/ericgu/archive/2004/01/12/57985.aspx), es hat einfach nicht genug Punkte bekommen. –

+0

@KirkWoll nur weil Java es aus der Box macht, macht es nicht unbedingt einen zwingenden Grund. Die gebrochene Varianz von Arrays in C# liegt auch an ihrer Existenz in Java ... war das eine gute Designentscheidung? Ich könnte mich irren und Typvarianz zurückgeben ist ein großartiges Feature in einer Sprache, also sag mir warum. Ihr Kommentar ist weder konstruktiv noch fügt er etwas hilfreiches zu diesem Thema hinzu. – InBetween

1

Sie können immer wickeln Sie das Verfahren in einem anderen Verfahren

public class Alpha { 
    public virtual Alpha DoSomething() { 
     return AlphaFactory.GetAlphaFromSomewhere(); 
    } 
} 
public class Beta : Alpha { 
    private Beta Helper() { 
     return BetaFactory.GetBetaFromSomewhere(); 
    } 
    public Beta DoSomething() { 
     return Helper(); 
    } 
    public override Alpha DoSomething() { 
     return Helper(); 
    } 
} 

Wenn es gibt viele Methoden, aber Sie könnten diese Wrapper automatisch generieren wollen. Wenn das zu anspruchsvoll ist, ist die Lösung von @recursive alles was übrig bleibt.