Question

Je suis nouveau dans toutes les fonctionnalités anonymes et j'ai besoin d'aide.J'ai fait fonctionner ce qui suit :

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));
}

Mais c'est totalement moche et j'aimerais que l'intérieur du Do soit une méthode anonyme ou même un lambda si c'est possible.J'ai essayé:

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

et

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

mais ça me donne

Impossible de convertir une méthode anonyme en type « System.Delegate » car il ne s’agit pas d’erreurs de compilation de type délégué**.

Qu'est-ce que je fais mal?


En raison de ce que Mark Ingram a publié, la meilleure réponse semble être la suivante, même si personne ne l'a explicitement dit :

public delegate void FakeSave(Transaction t);

Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; }));
Était-ce utile?

La solution

C'est un message d'erreur bien connu.Consultez le lien ci-dessous pour une discussion plus détaillée.

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

En gros, il vous suffit de mettre un casting devant votre délégué anonyme (votre expression lambda).

Au cas où le lien tomberait, voici une copie du message :

Ce sont des méthodes anonymes, pas des délégués anonymes.
Publié le 22 décembre 2007 par staceyw1

Ce n'est pas seulement un sujet de discussion parce que nous voulons être difficiles.Cela nous aide à raisonner sur ce qui se passe exactement.Pour être clair, il n'y a * pas de délégué anonyme.Ils n'existent pas (pas encore).Ce sont des "méthodes anonymes" - période.Cela importe la façon dont nous pensons à eux et comment nous en parlons.Jetons un coup d'œil à l'instruction de méthode anonyme "Delegate () {…}".Il s'agit en fait de deux opérations différentes et lorsque nous y pensons de cette façon, nous ne serons plus jamais confus.La première chose que le compilateur fait est de créer la méthode anonyme sous les couvertures en utilisant la signature du délégué inféré comme signature de la méthode.Il n'est pas correct de dire que la méthode est "sans nom" car elle a un nom et le compilateur l'affecte.Il est juste caché à la vue normale.La prochaine chose qu'il fait est de créer un objet délégué du type requis pour envelopper la méthode.C'est ce qu'on appelle l'inférence du délégué et peut être la source de cette confusion.Pour que cela fonctionne, le compilateur doit être capable de comprendre (c'est-à-direinférer) quel type de délégué il créera.Il doit s'agir d'un type de béton connu.Laissez écrire du code pour voir pourquoi.

private void MyMethod()
{
}

Ne compile pas :

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’

La ligne 1 ne se compile pas car le compilateur ne peut déduire aucun type de délégué.Il peut clairement voir la signature que nous désirons, mais il n'y a pas de délégué en béton que le compilateur peut voir.Cela pourrait créer un type de type de type anonyme pour nous, mais cela ne fonctionne pas comme ça.La ligne 2 ne se compile pas pour une raison similaire.Même si le compilateur connaît la signature de la méthode, nous ne lui donnons pas un type de délégué et il ne va pas seulement en choisir un qui fonctionnerait (pas quels effets secondaires pourraient avoir).La ligne 3 ne fonctionne pas parce que nous avons délibérément incompétent la signature de la méthode avec un délégué ayant une signature différente (comme WaitCallback prend et objet).

Compile :

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.

En revanche, ceux-ci fonctionnent.La ligne 1 fonctionne parce que nous disons au compilateur quel type de délégué à utiliser et qu'ils correspondent, donc cela fonctionne.La ligne 5 fonctionne pour la même raison.Remarque Nous avons utilisé la forme spéciale de "délégué" sans les parens.Le compilateur déduit la signature de la méthode du moulage et crée la méthode anonyme avec la même signature que le type de délégué inféré.La ligne 6 fonctionne parce que le myMethod () et l'action utilisent la même signature.

J'espère que ça aide.

Regarde aussi: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/

Autres conseils

Ce que Marc a dit.

Le problème est que Do prend un paramètre Delegate.Le compilateur ne peut pas convertir les méthodes anonymes en délégué, seulement un "type délégué", c'est-à-direun type concret dérivé de Delegate.

Si cette fonction Do avait pris Action<>, Action<,> ...etc.surcharges, vous n'auriez pas besoin du casting.

Le problème ne vient pas de la définition de votre délégué, c'est que le paramètre de la méthode Do() est de type System.Delegate et que le type de délégué généré par le compilateur (FakeSave) n'est pas implicitement converti en System.Delegate.

Essayez d'ajouter une distribution devant votre délégué anonyme :

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

Essayez quelque chose comme :

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

Notez l'EventHandler ajouté autour du délégué.

MODIFIER:pourrait ne pas fonctionner puisque les signatures de fonction d'EventHandler et du délégué ne sont pas les mêmes...La solution que vous avez ajoutée au bas de votre question est peut-être la seule solution.

Alternativement, vous pouvez créer un type de délégué générique :

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

Pour que le délégué ne soit pas spécifique à la transaction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top