Warum kann ich keine Action für / zu einem ThreadStart verwenden / umsetzen?

8

Beide sind Delegaten und haben die gleiche Signatur, aber ich kann Action nicht als ThreadStart verwenden.

Warum?

%Vor%

aber das scheint zu funktionieren:

%Vor%     
Rookian 21.03.2010, 20:46
quelle

8 Antworten

20

Wie andere bemerkt haben, besteht das Problem darin, dass Delegattypen nicht "strukturell" sind. Das heißt, sie haben keine Äquivalenz basierend auf ihrer "Struktur".

Nun, das ist wohl eine gute Sache für einige Arten. Wenn Sie

haben %Vor%

und

%Vor%

Offensichtlich wäre es ein Fehler, Instanzen von MyRectangle Variablen von YourRectangle zuzuweisen, nur weil sie beide aus vier Ints bestehen. Die Semantik der Ints ist unterschiedlich und daher sind die Typen nicht äquivalent.

Das gilt theoretisch auch für die Delegierten. Du könntest

haben %Vor%

wobei eine "reine" Funktion ohne Nebeneffekte und die gleiche Ausgabe bei gleicher Eingabe ist. Da jeder Pure logisch ein Func ist, aber nicht jeder Func ein Pure ist, sollte es keine strukturelle Typisierung zwischen ihnen geben.

In der Praxis unterstützt das Typsystem natürlich Begriffe wie "pure function" nicht sehr gut. Und in der Praxis ist die überwiegende Mehrheit der Versuche, zwischen den Delegattypen zu konvertieren, vollkommen sicher: Umwandlung von Func<int, bool> in Predicate<int> und so weiter.

Also, zwei Dinge, ein Blick nach hinten und ein Blick nach vorne. Rückwärts: Wenn wir es noch einmal machen müssten, würden die Delegierten wahrscheinlich strukturell in die CLI eingetippt werden. Sie wissen nicht immer, welche Funktionen nützlich sein werden, wenn Sie ein brandneues Framework entwerfen, und nicht-strukturelle Delegattypen haben sich bisher als nicht so nützlich erwiesen wie vielleicht erwartet. Vorwärts: Ich erwarte, dass in zukünftigen CLR-Versionen mehr Funktionen angezeigt werden, die eine strukturiertere Typisierung ermöglichen. Das "no pia" -Feature in C # 4 zum Beispiel geht darum, zwei Typen, die semantisch und strukturell gleich sind, aber in verschiedenen Assemblies definiert sind, logisch strukturell zu vereinheitlichen.

    
Eric Lippert 21.03.2010, 21:53
quelle
4

Sie bemerken, dass Action ein Typ ist und das "Lambda" in Ihrem zweiten Beispiel nicht.

Wahrscheinlich sind sie gleich, aber Sie verwenden einen konkreten Framework-Typ, wenn Sie Action verwenden, während der Compiler die Signatur des Lambda ableitet.

EDIT: um klar zu sein:

Aktion ist ein Delegattyp, der not ein ThreadStart-Delegat ist. Sie können also den Lambda-Ausdruck beiden zuweisen, aber Sie können nicht beide verwenden, um einen Thread zu starten.

Im zweiten Beispiel geben Sie dem Compiler die Möglichkeit, den Typ des Delegaten abzuleiten, und ohne große Überraschung kann er den Lambda-Ausdruck dem Typ ThreadStart zuweisen.

    
Sky Sanders 21.03.2010 20:59
quelle
3

Delegierte mit der gleichen Unterschrift sind in den Augen der CLR nicht gleich - sie sind völlig unterschiedliche Typen.

    
Zach Johnson 21.03.2010 20:53
quelle
3

Ich glaube, das sollte funktionieren?

%Vor%     
Spencer Ruport 21.03.2010 21:33
quelle
3

Die Grundform dieses Fehlers ist:

%Vor%

So könnten Sie Ihre erste Probe "lösen", indem Sie den richtigen Delegattyp verwenden:

%Vor%     
Henk Holterman 21.03.2010 20:55
quelle
2

Ich denke, das folgende Wort in Abschnitt 26.3.1 der C # -Sprachspezifikation ist wichtig:

  

Ähnlich wie bei einem   anonymer Methodenausdruck, a   Lambda-Expression wird als a eingestuft   Wert mit speziellen Konvertierungsregeln.   Der Wert hat keinen Typ, kann aber   implizit in a konvertiert werden   kompatibler Delegattyp   Insbesondere ist ein Delegattyp D   kompatibel mit einem Lambda-Ausdruck L   zur Verfügung gestellt:
[List elided]

Was verhindert, dass Code wie dieser kompiliert wird:

%Vor%

Was zu:

führt %Vor%

Wird vom Compiler abgelehnt, wenn Konvertierungen von einem Delegattyp zu einem anderen nicht zulässig sind, auch wenn ihre Signaturen kompatibel sind. Erzwingen:

%Vor%

Welches kompiliert ohne Probleme.

Irrelevantes Bonus-Feature: Bei ersten Usability-Tests auf dem ersten Apple Mac wurde ein Problem mit der ersten Version der OK-Schaltfläche in den Dialogen festgestellt, die eine serifenlose Schriftart verwendeten. Die Benutzer klickten stattdessen oft auf "Abbrechen", mit sichtbarer Angst. Nach mehreren Interviews gab ein Nutzer schließlich das Problem zu: "Ich hasse es, wenn ein Computer mich einen Dolt nennt!"

Nun, ein Compiler, der dich vielleicht als Dummkopf bezeichnet, ist nicht so irrelevant:)

    
Hans Passant 21.03.2010 22:00
quelle
1

Versuchen Sie:

%Vor%

oder

%Vor%

Sie versuchen, ein Argument vom Typ "Action" an einen Konstruktor zu übergeben, der einen ThreadStart verwendet. Es ist keine implizite Konvertierung definiert, daher müssen Sie den ThreadStart-Konstruktor manuell aufrufen.

    
Alan 21.03.2010 20:51
quelle
1

Weil der Threadstart ein separater Delegattyp ist und Action nicht in ThreadStart konvertiert werden kann.

Dieser Fall funktioniert, weil hier Ihr Lambda vom Compiler als ThreadStart behandelt wird:

%Vor%     
Andrew Bezzub 21.03.2010 20:53
quelle