Wie kann ich den Rückgabetyp eines FuncT durch Reflektion erhalten?

8

Ich habe die folgende Typhierarchie:

%Vor%

Ich habe auch eine Methode, die die Instanz eines bestimmten Typs bei Bedarf auflöst (man denke an die IOC eines Laien):

%Vor%

Ich muss den Typ von T in Func<T> herausfinden, aber wenn ich es versuche:

%Vor%

Ich bekomme Controller anstelle von PersonController und OrderController .

Irgendwelche Ideen?

Aktualisierung:

Ich danke allen für die Bereitstellung so detaillierter Antworten und Beispiele. Sie haben mich dazu gebracht, die API zu überdenken und hier ist, was ich endlich herausgefunden habe, was dazu dient, was ich erreichen wollte: %Vor%

Und hier sind einige Anwendungsbeispiele:

%Vor%     
MaYaN 30.11.2016, 20:46
quelle

4 Antworten

8

Jede Methode hat einen Rückgabetyp, der in der Assembly gespeichert ist. Sie haben angegeben, dass der Rückgabetyp Ihrer Methode Controller ist. Dies ist das einzige, was als Information garantiert ist ( Das wissen wir, ohne die Methode auszuführen - auch zur Kompilierzeit )

Wir wissen also, dass die Methode Controller oder alles, was davon abgeleitet ist, zurückgeben soll. Wir können nie wissen, was der Laufzeittyp ist, bis wir diese Methode tatsächlich aufrufen.

Was ist zum Beispiel, wenn die Methode einen Code wie folgt hat:

%Vor%

Wenn Sie den Laufzeittyp des zurückgegebenen Objekts abrufen müssen, müssen Sie:

%Vor%     
user3185569 30.11.2016, 20:55
quelle
6

Lambdas in C # erhalten ihren Typ basierend auf dem Ausdruck, dem sie zugewiesen sind. Zum Beispiel:

%Vor%

Macht die Lambda x => x a string => string Funktion, mit der Begründung, dass dies die Variable d erwartet.

Warum ist das relevant? Weil Sie im folgenden Code eine ähnliche Erwartung für die folgenden Lambdas erstellen:

%Vor%

Es wird erwartet, dass diese Lambdas vom Typ Func<Controller> sind. Wenn der Compiler die Lambda-Körper für den Typ betrachtet, würde dies zu einer anderen Schlussfolgerung führen, nämlich dass eine Func<PersonController> und die andere Func<OrderController> ist, wobei beide Arten von Func<Controller> sind. Aber der Compiler betrachtet den Körper nicht nach dem Typ, er betrachtet die Variable und die "Variable" ist in diesem Fall der Array-Slot.

Daher wird der Compiler diese Delegaten nicht als diese Methoden generieren:

%Vor%

Aber wie diese Methoden:

%Vor%

Wenn diese Delegaten in das Array eingefügt werden, bleiben daher nur die Typinformationen der Signaturen erhalten, während die tatsächlichen Typinformationen der Lambda-Körper verloren gehen.

Aber es gibt einen Weg, um die Informationen über die Lambda-Körper zu erhalten, und dann diese Informationen anstelle der Delegiertensignaturen zu überprüfen. Sie können Ausdrucksbäume verwenden, die dem Compiler ermöglichen, Code als Daten zu behandeln und im Wesentlichen Baumobjekte zu generieren, die für das Lambda stehen, anstelle der eigentlichen Methode implementiert das Lambda.

Ihre Syntax ist fast identisch mit der von Lambda:

%Vor%

Der Unterschied besteht nun darin, dass diese Objekte keine Funktionen, sondern Repräsentationen von Funktionen sind. Sie können diese Repräsentation durchqueren und sehr einfach den Typ ihres Ausdrucks auf oberster Ebene finden:

%Vor%

Schließlich können Sie diese Repräsentationen auch in tatsächliche Funktionen umwandeln, wenn Sie sie auch ausführen wollen:

%Vor%     
quelle
3

Das Problem ist, dass dasselbe T auf jeden Typ in Ihrem Array angewendet werden muss. In

%Vor%

Was ist dein T ? Ist es PersonController ? Ist es OrderController ? Um es Ihrem Anwendungsfall anzupassen, kann es nur eine Klasse sein, die eine Oberklasse von PersonController und OrderController ist, während sie eine Unterklasse von Controller ist. Daher kann T nur eine Klasse sein: Controller (vorausgesetzt, die beiden Klassen haben keine gemeinsame Basisklasse, die Controller erweitert). Es macht keinen Sinn, diese Klasse generisch zu machen. Es ist genau das gleiche:

%Vor%

Anstelle eines Arrays von Func<Controller> -Instanzen kann es sinnvoller sein, ein auf Ihren Rückgabetyp getatetes Wörterbuch zu übergeben:

%Vor%

Eine Instanz von Func<Controller> enthält einfach nicht genug Informationen, um den Typ ihres Rückgabewerts selbst zu bestimmen: nicht ohne sie auszuwerten. Und selbst wenn Sie es auswerten, denken Sie daran, dass eine Funktion eine Blackbox ist. Nur weil es einmal PersonController zurückgibt, heißt das nicht, dass es beim nächsten Aufruf kein OrderController zurückgibt.

    
Rob Lyndon 30.11.2016 21:06
quelle
2

So funktioniert es, wenn Sie Ihr Array instanziieren, geben Sie an, dass es Func -Objekte vom Typ Controller speichern würde, jetzt stempeln Sie die Untertypenobjekte innerhalb des Arrays von Func , Das Resolve, weiß nicht, was der tatsächliche Typ ist, es sei denn, Sie rufen GetType() auf, um den tatsächlichen Typ zu bestimmen, es weiß nur, dass T vom Typ Controller wegen der Einschränkung ist, dh where T : Controller

    
Ehsan Sajjad 30.11.2016 20:57
quelle

Tags und Links