2008-09-12 10 views
21

Ich bin neu bei allen anonymen Funktionen und brauche etwas Hilfe. Ich habe folgendes bekommen zu arbeiten:Konvertieren Sie diesen Delegaten in eine anonyme Methode oder Lambda

public void FakeSaveWithMessage(Transaction t) 
{ 
    t.Message = "I drink goats blood"; 
} 

public delegate void FakeSave(Transaction t); 

public void SampleTestFunction() 
{ 
    Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage)); 
} 

Aber das ist total hässlich, und ich möchte das Innere des Do habe eine anonyme Methode oder auch ein Lambda sein, wenn es möglich ist. Ich habe versucht:

Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; }); 

und

Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; }); 

aber diese geben mir

nicht anonyme Methode konvertieren kann ‚System.Delegate‘ zu geben, weil es kein Delegattyp ist ** kompilieren Fehler .

Was mache ich falsch?


Aufgrund dessen, was Mark Ingram geschrieben, scheint die beste Antwort, obwohl niemand explizit gesagt wird, ist, dies zu tun:

public delegate void FakeSave(Transaction t); 

Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; })); 

Antwort

27

Das ist eine bekannte Fehlermeldung. Weitere Informationen finden Sie im folgenden Link.

http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/

Im Grunde brauchen Sie nur eine Besetzung vor Ihrem anonymen Delegaten (Ihr Lambda-Ausdruck) zu setzen.

Falls der Link geht immer nach unten, hier ist eine Kopie der Post:

Sie sind Anonyme Methoden, nicht Anonym Die Delegierten.
am 22. Dezember Geschrieben 2007 von staceyw1

Es ist nicht nur ein Gesprächsthema, weil wir schwierig sein wollen. Es hilft uns Grund über was genau los ist. Um klar zu sein, gibt es * keine solche Sache als anonymer Delegierter. Sie existieren nicht (noch nicht). Sie sind "Anonymous Methoden" - Zeitraum. Es ist wichtig, wie wir über sie denken und wie wir über sie reden.Werfen wir einen Blick auf die anonyme Methode Anweisung "Delegate() {...}". Dies ist eigentlich zwei verschiedene Operationen und wenn wir daran denken auf diese Weise werden wir nie wieder verwechselt werden. Das erste, was der Compiler tut ist die anonyme Methode unter den Abdeckungen mit der abgeleiteten Delegiertensignatur als Methode Signatur zu erstellen. Es ist nicht korrekt zu sagen die Methode ist "unbenannt", weil es einen Namen hat und der Compiler es zuweist. Es ist nur versteckt von normale Ansicht. Das nächste, was es tut ist ein Delegate-Objekt der erforderlichen Typ, um die Methode zu umbrechen. Diese heißt Delegate Inferenz und kann die Quelle dieser Verwirrung sein. Für dies zu arbeiten, muss der Compiler in der Lage sein herauszufinden (d. H. Abzuleiten), was Delegate-Typ wird es erstellen. Es hat einen bekannten Betontyp zu sein. Lassen Sie einen Code schreiben, um zu sehen, warum.

private void MyMethod() 
{ 
} 

lässt sich nicht kompilieren:

1) Delegate d = delegate() { };      // Cannot convert anonymous method to type ‘System.Delegate’ because it is not a delegate type 
2) Delegate d2 = MyMethod;       // Cannot convert method group ‘MyMethod’ to non-delegate type ‘System.Delegate’ 
3) Delegate d3 = (WaitCallback)MyMethod; // No overload for ‘MyMethod’ matches delegate ‘System.Threading.WaitCallback’ 

Linie 1 nicht kompiliert, da der Compiler keinen Delegierten Typ ableiten kann. Es kann deutlich die Signatur sehen, die wir wünschen, aber es gibt keinen konkreten Delegattyp, den der Compiler sehen kann. Es könnte einen anonymen Typ von Art Vertreter für uns erstellen, aber es funktioniert nicht so. Die Zeile 2 kompiliert aus einem ähnlichen Grund nicht . Auch obwohl der Compiler die Methode Unterschrift kennt, werden wir es nicht einen Delegattyp geben und es ist nicht nur eine auswählen, geht die Arbeit (Effekte nicht, welche Seite, könnte haben) passieren würde. Zeile 3 funktioniert nicht, weil wir die Methode absichtlich mit einem Delegaten mit einer unterschiedlichen Signatur (wie WaitCallback übernimmt und Objekt) nicht übereinstimmte.

Compiliert:

4) Delegate d4 = (MethodInvoker)MyMethod; // Works because we cast to a delegate type of the same signature. 
5) Delegate d5 = (Action)delegate { };    // Works for same reason as d4. 
6) Action d6 = MyMethod;        // Delegate inference at work here. New Action delegate is created and assigned. 

Im Gegensatz dazu diese Arbeit. Zeile 1 funktioniert , weil wir dem Compiler mitteilen, was Delegate-Typ zu verwenden und sie übereinstimmen, , so dass es funktioniert. Zeile 5 funktioniert für den gleichen Grund. Beachten Sie, dass wir die spezielle Form der "Delegierten" ohne die Parens verwendet haben. Der Compiler leitet die Methode Signatur aus dem Cast und erstellt die anonyme Methode mit der gleichen Signatur als abgeleiteten Delegaten Typ. Zeile 6 funktioniert, weil die MyMethod() und Aktion dieselbe Signatur verwenden.

Ich hoffe, das hilft.

Siehe auch: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/

+1

gute Verbindung, aber ich verstehe immer noch nicht, warum * * der Compiler es nicht automatisch gegossen (wie es mit Lambda-Syntax der Fall ist) –

+0

Link ist kaputt. –

+0

Arbeitest du immer noch für mich? –

0

Versuchen Sie so etwas wie:

Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; })); 

Hinweis der hinzugefügte EventHandler um den Delegaten.

EDIT: funktioniert möglicherweise nicht, da die Funktionssignaturen von EventHandler und der Delegat nicht identisch sind ... Die Lösung, die Sie am Ende Ihrer Frage hinzugefügt haben, ist möglicherweise der einzige Weg.

Alternativ können Sie einen allgemeinen Delegattyp erstellen:

public delegate void UnitTestingDelegate<T>(T thing); 

Damit die Delegierten nicht Transaktion spezifisch ist.

3

Was sagte Mark.

Das Problem ist, dass Do einen Delegate-Parameter übernimmt. Der Compiler kann die anonymen Methoden nicht in Delegate konvertieren, sondern nur einen "Delegate-Typ", d. H. Einen konkreten Typ, der von Delegate abgeleitet wird.

Wenn diese Do-Funktion Aktion <>, Aktion <,> ... usw. Überladungen ausgeführt hätte, würden Sie die Besetzung nicht benötigen.

1

Das Problem liegt nicht in Ihrer Delegatendefinition, sondern darin, dass der Parameter der Do() -Methode vom Typ System.Delegate ist und der vom Compiler generierte Delegattyp (FakeSave) nicht implizit in System.Delegate konvertiert wird.

Versuchen Sie, eine Guss vor Ihrem anonymen Delegaten hinzu:

Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; }); 
+0

Dies funktioniert nicht Delegat {} ist eine anonyme Funktion - es ist kein Typ. System.Delegate ist die abstrakte Basisklasse, die die implizite Basis aller deklarierten Delegattypen ist. Es gibt wirklich 3 verschiedene Anwendungen des Wortdelegaten hier! Sie können einen beliebigen Delegattyp (z. B. EvantHandler, Action, Func ) in den Delegate-Modus versetzen, aber Sie müssen zuerst einen Delegattyp erstellen. –