2 Stimmen

Typinferenz über IEnumerable<T>

Es gibt ein paar Beiträge bereits auf Stack Overflow über diese Art von Sache, aber nicht genau das gleiche - so entschuldigt im Voraus, wenn dies etwas ist, das bereits beantwortet wurde.

Warum funktioniert das nicht?

public class MyBase { }

public class MyUtils
{
    public bool Foo<T> (T myObject) { return true; }
    public bool Foo (MyBase myBaseObject) { return false; }

    public void Go<T> (IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            // this test fails
            Assert.IsFalse (Foo (item));
        }
    }
}

Wenn ich oben Go() aufrufe und eine Ladung von MyBase-Objekten übergebe, wird jeder Aufruf von Foo die generische Funktion Foo () aufrufen, die true zurückgibt.

new MyUtils ().Go (new MyBase[] { new MyBase (), new MyBase () });      

Warum wird nicht stattdessen die spezielle MyBase-Version aufgerufen? Wenn ich Foo (new MyBase ()) direkt aufrufe, wird korrekt abgeleitet, welcher Aufruf zu tätigen ist. Ist dies, weil der Mangel an Kovarianz für Sammlungen in C#3, oder bin ich einfach nur dumm und nicht tun dies richtig?

Merci !

Isaac

1voto

Orion Edwards Punkte 117361

Die "spezialisierte" Methode wird nicht aufgerufen, da der Compiler die Methode auswählt, die aufgerufen werden soll, wenn das Programm (in diesem Fall ist es die Go Funktion) ist zusammengestellt , no wenn sie ausgeführt wird.

Der Compiler kompiliert die Go ist die einzige Information, die sie hat, dass es ein Objekt des Typs T . Es hat keine Ahnung, dass Sie es zu einem späteren Zeitpunkt mit einem Objekt des Typs MyBase . Die einzige Möglichkeit, die sie hat, ist die Wahl der Foo<T> Überladung und bindet sie daher in das kompilierte Programm ein.

Wenn Sie möchten, dass eine Anwendung zur Laufzeit Überladungen auswählt und die beste Überladung auswählt, indem sie sich das Objekt ansieht, während die Anwendung läuft, nennt man das "Dynamic Dispatch" und wird nur von dynamischen Sprachen wie Ruby, Python, PHP usw. verwendet.

C#3 ist vollständig statisch und unterstützt dies nicht. Sie müssten eine if-Anweisung in Ihrem Code schreiben, um den Typ zu überprüfen, wenn Sie wollten, dass es auf diese Weise funktioniert. C#4 hingegen bietet eine gewisse dynamische Unterstützung. Wenn Sie diesen Code in C# 4 schreiben würden, könnten Sie die Funktion 'Go' wie folgt deklarieren:

 public void Go<T> (IEnumerable<dynamic> items)

Dann würde es dynamisches Dispatching zur Laufzeit verwenden, um auszuwählen, welche Überladung aufgerufen wird, und würde die Überladung aufrufen, die darauf spezialisiert ist, die MyBase

0voto

Laurent Etiemble Punkte 26361

Nach den C#-Spezifikationen (7.4.3.2) ist die nicht-generische Methode besser als die generische, so dass sie ausgewählt werden sollte.

Aber ich denke, dass die generische in Ihrem Fall aufgegriffen wird, weil sie in einem generischen Aufrufkontext (der "foreach"-Schleife) aufgerufen wird.

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