Pregunta

Soy nuevo en todas las funciones anónimas y necesito ayuda.He conseguido que funcione lo siguiente:

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 que el interior del Do fuera un método anónimo o incluso una lambda si es posible.Lo intenté:

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 un método anónimo al tipo 'System.Delegate' porque no es un tipo de delegado** errores de compilación.

¿Qué estoy haciendo mal?


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

public delegate void FakeSave(Transaction t);

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

Solución

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

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

Básicamente sólo necesitas poner un elenco delante de tu delegado anónimo (tu expresión lambda).

En caso de que el enlace alguna vez se caiga, aquí hay una copia de la publicación:

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

No es solo un tema de conversación porque queremos ser difíciles.Nos ayuda a razonar qué está pasando exactamente.Para ser claros, no existe *algo como un delegado anónimo.No existen (aún no).Son "Métodos anónimos" - Período.Importa cómo pensamos en ellos y en cómo hablamos de ellos.Echemos un vistazo a la declaración de método anónimo "delegado () {...}".Estas son en realidad dos operaciones diferentes y cuando lo pensamos de esta manera, nunca volveremos a confundirnos.Lo primero que hace el compilador es crear el método anónimo debajo de las cubiertas utilizando la firma delegada inferida como firma del método.No es correcto decir que el método es "sin nombre" porque tiene un nombre y el compilador lo asigna.Está oculto a la vista normal.Lo siguiente que hace es crear un objeto delegado del tipo requerido para envolver el método.Esto se llama inferencia delegada y puede ser la fuente de esta confusión.Para que esto funcione, el compilador debe ser capaz de resolver (es decir,inferir) qué tipo delegado creará.Tiene que ser un tipo de concreto conocido.Deje escribir algún código para ver por qué.

private void MyMethod()
{
}

No 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’

La línea 1 no se compila porque el compilador no puede inferir ningún tipo de delegado.Puede ver claramente la firma que deseamos, pero no hay un delegado de concreto tipo que el compilador pueda ver.Podría crear un tipo anónimo de delegado de tipo para nosotros, pero no funciona así.La línea 2 no se compila por una razón similar.A pesar de que el compilador conoce la firma del método, no le estamos dando un tipo de delegado y no solo va a elegir uno que funcione (no qué efectos secundarios podrían tener).La línea 3 no funciona porque no coincidimos deliberadamente la firma del método con un delegado que tiene una firma diferente (como toma WaitCallback 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 funcionan.La línea 1 funciona porque le decimos al compilador qué tipo delegado usa y que coinciden, por lo que funciona.La línea 5 funciona por la misma razón.Tenga en cuenta que utilizamos la forma especial de "delegado" sin el Parens.El compilador infiere la firma del método del reparto y crea el método anónimo con la misma firma que el tipo delegado inferido.La línea 6 funciona porque el mymethod () y la acción usan la misma firma.

Espero que esto ayude.

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

Otros consejos

Lo que dijo Marcos.

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

Si esa función Do hubiera tomado Acción<>, Acción<,>...etc.sobrecargas, no necesitarías el yeso.

El problema no está en su 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.

Intente agregar un elenco frente a su delegado anónimo:

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

Pruebe algo como:

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

Tenga en cuenta el EventHandler agregado alrededor del delegado.

EDITAR:Es posible que no funcione ya que las firmas de funciones de EventHandler y el delegado no son las mismas...La solución que agregó al final de su pregunta puede ser la única manera.

Como alternativa, puedes crear un tipo de delegado genérico:

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

Para que el delegado no sea específico de la transacción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top