Extraño comportamiento usando yield y manejo de exceptiones
- By yohan.jasdid
- In Bits
- With No Comments
- Tagged with yield postsharp behavior
- On 30 Nov | '2010

Trabajando en un proyecto y de alguna manera llegue a ver el escenario que a continuacion describo al momento de utilizar el operaror yield y manejo de excepciones con PostSharp..
Resulta que cuando utilizas yield para regresar una lista tipo IEnumerable y en el metodo hijo en el cual utilizas yield ocurre una exception hay un comportamiento un tanto raro o al menos para mi que no soy un experto en C#, quise hacer un proyecto de ejemplo para ilustrar mejor el comportamiento que describo, a continuacion pongo la clase de un proyecto de consola que hice:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PostSharpYieldSample
{
public class Program
{
public static void Main(string[] args)
{
ParentMethod();
Console.WriteLine("press any key to end.");
Console.ReadLine();
}
private static IEnumerable<string> _myList;
/// <summary>
/// Parent
/// </summary>
[ExceptionHandlerAspect]
public static void ParentMethod()
{
Console.WriteLine("In parent Method.");
_myList = ChildYieldMethod();
// comment the lines below to "EAT" the exception message
foreach (string str in _myList)
Console.Write(str);
}
/// <summary>
/// Child method using yield
/// </summary>
/// <returns></returns>
public static IEnumerable<string> ChildYieldMethod()
{
Console.WriteLine("In child Method.");
String[] data = { "Item 1", "Item 2", "Item 3" };
foreach (string myString in data)
{
yield return myString;
throw new Exception("Some exception happen here");
}
}
}
}
Como se puede ver estoy utilizando un Aspecto de PostSharp en el metodo ParentMethod() para “cachar” todas las excepciones que pudieran ocurrir en el metodo, a continuacion enlisto el aspecto que estoy utilizando:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Aspects;
using System.Diagnostics;
namespace PostSharpYieldSample
{
/// <summary>
/// Aspect class that handles errors using postsharp
/// </summary>
[Serializable]
public sealed class ExceptionHandlerAspect : OnExceptionAspect
{
/// <summary>
/// The flow behavior to use.
/// </summary>
private FlowBehavior flowBehavior;
/// <summary>
/// Default Constructor
/// </summary>
public ExceptionHandlerAspect()
: this(FlowBehavior.Return)
{
}
/// <summary>
/// Creates an instance specifying the flow behavior to use
/// </summary>
/// <param name="flowBehavior">The flow behavior</param>
public ExceptionHandlerAspect(FlowBehavior flowBehavior)
{
this.flowBehavior = flowBehavior;
}
/// <summary>
/// Method invoked upon failure of the method to which the current
/// aspect is applied.
/// </summary>
/// <param name="args">Information about the method being executed.</param>
public override void OnException(MethodExecutionArgs args)
{
string errorInfo = string.Format("{0}() {1} - PostSharp message.", args.Method.Name, args.Exception.Message);
Console.WriteLine(errorInfo);
args.FlowBehavior = flowBehavior;
}
}
}
Este aspecto es muy sencillo y lo utilice solo para fines de la demostracion y lo unico que hace es que me regresa un mensaje personalizado de la excepcion que ocurrio en el metodo donde se definio el aspecto (atributo), al ejecutar la aplicacion de ejemplo se vera la siguiente pantalla:
Cosa que tiene sentido ya que el flujo del programa entro en el metodo donde utilizo yield y solo regreso el primer elemento para despues lanzar la excepcion especificada, en este caso PostSharp “atrapa” correctamente la excepcion y la muestra en pantalla, este es el comportamiennto esperado, El problema viene cuando comentamos las lineas del parent method donde se hace referencia a la lista que se lleno mediante yield, estas lineas comentadas son las siguientes:
// comment the lines below to "EAT" the exception message
//foreach (string str in _myList)
// Console.Write(str);
Al momento de comentar estas lineas y volver a ejecutar el programa algo “raro” ocurre con la excepcion, lo que ocurre es que practicamente la excepcion es omitida o practicamente nuca llegamos a ejecutar el metodo donde utilizamos yield, el resultado luciria algo como lo siguiente:
Habra que investigar mas sobre lo que la palabra reservada yield hace en este caso internamente ya que a mi punto de vista no es un comportamiento obvio al que uno concluiria facilmente, a continuacion pongo el enlace del codigo fuente de la aplicacion ejemplo..
Pd. Creo que se me olvido hablar un poco mas acerca de PostSharp y programacion orientada a aspectos, es buen tema para un post que publicare mas adelante en estos dias por si te interesa saber mas sobre el tema de todos modos en la red hay mucha informacion sobre ello..
Saludos!












