2008-09-12 20 views
21

Soy nuevo en todas las funciones anónimas y necesito ayuda. He conseguido lo siguiente para trabajar:Convierta este delegado a un método anónimo o 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)); 
} 

Pero esto es totalmente feo y me gustaría tener el interior del hacer para ser un método anónimo o incluso una lambda, si es posible. Probé:

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

y

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

pero estos me dan

No se puede convertir método anónimo al tipo 'System.Delegate' porque no es un tipo de delegado ** Los errores de compilación .

¿Qué estoy haciendo mal?


Debido a lo que Mark Ingram publicada, parece ser la mejor respuesta, aunque nadie ha dicho explícitamente, es de hacer esto:

public delegate void FakeSave(Transaction t); 

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

Respuesta

27

Ese es un mensaje de error bien conocido. Consulte el enlace a continuación para una discusión más detallada.

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

Básicamente, usted sólo tiene que poner un yeso en la parte delantera de su delegado anónimas (su expresión lambda).

En caso de que el enlace nunca se cae, aquí es una copia del mensaje:

Son métodos anónimos, no delegados anónimos.
Publicado el 22 de diciembre de 2007 por staceyw1

No es sólo un tema de conversación porque queremos ser difícil. Nos ayuda razón de qué está pasando exactamente. Para ser claros, no existe * ningún elemento como delegado anónimo. No existen (todavía no). Son "Anónimos Métodos" - punto. Importa en cómo pensamos en ellos y cómo hablamos de ellos .Echemos un vistazo a la declaración de método anónimo "delegate() {...}". Esto es en realidad dos operaciones diferentes y cuando lo pensamos de esta manera, nunca más volveremos a confundir . Lo primero que hace el compilador es crear el método anónimo bajo las cubiertas utilizando la firma delegada inferir como el método firma. No es correcto decir el método es "sin nombre" porque tiene un nombre y el compilador lo asigna. Simplemente está oculto desde vista normal. Lo siguiente que hace es crear un objeto delegado del tipo requerido para envolver el método. Este se denomina inferencia delegada y puede ser el origen de esta confusión. Para que funcione, el compilador debe ser capaz de determinar (es decir, inferir) qué tipo de delegado creará. Tiene para ser un tipo concreto conocido. Deje escribir un código para ver por qué.

private void MyMethod() 
{ 
} 

no se compila:

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’ 

Línea 1 no se compila porque el compilador no puede deducir cualquier delegado tipo. Puede ver claramente la firma que deseamos, pero no hay un tipo de delegado concreto que el compilador pueda ver. Podría crear un tipo anónimo de tipo delegado de tipo para nosotros, pero no funciona así. La línea 2 no compila por una razón similar. Incluso aunque el compilador sabe la firma del método , nosotros no estamos dando un tipo delegado y no sólo va escoger uno que le pasaría a trabajar (no lo efectos secundarios que podrían tener ). La línea 3 no funciona porque intencionalmente no coincidimos con la firma del método con un delegado que tiene una firma diferente (como WaitCallback toma y objeto).

Compila:

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. 

Por el contrario, estos trabajos. La línea 1 funciona porque le decimos al compilador qué tipo de delegado usar y concuerdan, para que funcione. La línea 5 funciona para el misma razón. Tenga en cuenta que usamos la forma especial de "delegar" sin los paréntesis. El compilador infiere la firma del método del molde y crea el método anónimo con la misma firma que el tipo de delegado inferido . La línea 6 funciona porque MyMethod() y Action usan la misma firma .

Espero que esto ayude.

Véase también: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/

+1

Buen enlace, pero sigo sin entender por qué * * el compilador no lo echó automágicamente (como lo hace con la sintaxis lambda) –

+0

El enlace está roto. –

+0

¿Sigue trabajando para mí? –

0

Pruebe algo como:

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

Nota el EventHandler agregado alrededor del delegado.

EDITAR: podría no funcionar ya que las firmas de funciones de EventHandler y del delegado no son las mismas ... La solución que agregó al final de su pregunta puede ser la única.

Alternativamente, se puede crear un tipo de delegado genérico:

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

Para que el delegado no es transacción específica.

3

Lo dijo Mark.

El problema es que toma un parámetro Do Delegado. El compilador no puede convertir los métodos anónimos al Delegado, sólo un "tipo de delegado" es decir, un tipo concreto derivado de Delegado.

Si esa función Do ha tomado acción <>, acción <,> ... etc. sobrecargas, no necesitaría el reparto.

1

El problema no es con la definición de delegado, es que el parámetro del método Do() es de tipo System.Delegate y el tipo de delegado generado por el compilador (FakeSave) no se convierte implícitamente a System.Delegate.

trate de añadir un fundido en frente de su delegado en el anonimato:

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

Esto no funciona delegado {} es una función anónima - no es un tipo. System.Delegate es la clase base abstracta que es la base implícita de todos los tipos de delegado declarados. ¡En realidad hay 3 usos diferentes de la palabra delegado aquí! Puede abatido cualquier tipo de delegado (como EvantHandler, Acción, Func ) delegar, pero hay que crear realmente un tipo de delegado primera! –

Cuestiones relacionadas