2012-06-07 17 views
6

tengo un método que se puede escribir muy cuidadosamente a través del método de encadenamiento:método de encadenamiento de LINQ y error granular manejo

return viewer.ServerReport.GetParameters() 
    .Single(p => p.Name == Convention.Ssrs.RegionParamName) 
    .ValidValues 
    .Select(v => v.Value); 

Sin embargo, me gustaría ser capaz de hacer algunas comprobaciones en cada punto como deseo brinde información de diagnóstico útil si alguno de los métodos encadenados arroja resultados inesperados.

Para lograr esto, necesito dividir todo mi encadenamiento y seguir cada llamada con un bloque if. Hace que el código sea mucho menos legible.

Idealmente, me gustaría poder realizar algunas llamadas a métodos encadenados que me permitan manejar resultados inesperados en cada punto (por ejemplo, arrojar una excepción significativa como new ConventionException("The report contains no parameter") si el primer método devuelve una colección vacía). ¿Alguien puede sugerir una manera simple de lograr tal cosa?

Editar:

Este es el resultado del uso de @ respuesta de JeffreyZhao:

return viewer.ServerReport.GetParameters() 
    .Assert(result => result.Any(), "The report contains no parameter") 
    .SingleOrDefault(p => p.Name == Convention.Ssrs.RegionParamName) 
    .Assert(result => result != null, "The report does not contain a region parameter") 
    .ValidValues 
    .Select(v => v.Value) 
    .Assert(result => result.Any(), "The region parameter in the report does not contain any valid value"); 

Respuesta

7

Tal vez usted puede utilizar este enfoque.

static T Check<T>(this T value) 
{ 
    if (...) throw ...; 

    return value; 
} 

a continuación:

xxx.Single(...).Check().Select(...).Check()... 

Actualización:

Puede incluso:

static T Validate<T>(this T value, Func<T, bool> validate, string errorMessage) 
{ 
    if (!validate(value)) 
     throw new ValidationFailedException(errorMessage); 

    return value; 
} 

a continuación:

xxxx.Single() 
    .Validate(v => v > 0, "Must be greater than zero") 
    .NextStep() 
    .Validate(...); 
+0

Esto se ve bien. Y dada la naturaleza de la comprobación de errores, sospecho que puede ser que los métodos genéricos no sean necesarios (es decir, a menudo la naturaleza de la comprobación de errores es específica para un tipo dado). El enfoque general de tener un método de extensión que simplemente devuelve la entrada sin modificar es exactamente lo que se necesita. – Chris

+0

Tienes razón.Agregué un método 'Validate' más general y en ese caso se requiere el genérico. –

+0

Agradable. Ojalá pudiera +1 de nuevo para esa pequeña y agradable función 'Validate'. :) – Chris

1

Se puede dividir fácilmente el proceso en etapas separadas con variables locales:

var result1 = viewer.ServerReport.GetParameters(); 
var result2 = result1.Single(p => p.Name == Convention.Ssrs.RegionParamName); 
var result3 = result2.ValidValues; 
var result4 = result3.Select(v => v.Value); 
return result4; 

Ahora usted puede hacer todas las comprobaciones que desee entre los pasos.

Sin embargo, tenga en cuenta que algunos resultados en realidad no funcionan. El último paso, por ejemplo, no produce una lista como resultado, produce un enumerable que se lee desde ValidValues, por lo que cualquier error en ese paso ocurriría cuando use el resultado, no dentro de este método. Es posible que desee agregar .ToList() al final de algunos pasos para obtener el resultado.

1

Considere el uso de Code Contracts (por ejemplo, agregue la condición posterior a ServerReport.GetParameters para asegurarse de que los métodos no devuelvan la colección vacía). Permiten hacer lo que desee de una manera más elegante, que escribir su propia lógica de comprobación.

class ReportParameter { } 
class ServerReport 
{ 
    public ReportParameter[] GetParameters() 
    { 
     Contract.Ensures(Contract.Result<ReportParameter[]>() != null && Contract.Result<ReportParameter[]>().Length > 0, 
      Resource1.Oops); 

     // here's some logic to build parameters array... 
     return new ReportParameter[0]; 
    } 
} 

Uso:

// Oops! I need at least one parameter! 
var parameters = new ServerReport().GetParameters(); 
+0

Eso suena ideal. Sin embargo, en mi caso particular, son los datos los que deben ajustarse a ciertas expectativas, por lo que el análisis estático no podría ser de ayuda (me doy cuenta de que esto también proporciona comprobaciones de tiempo de ejecución, pero no estoy seguro de que este nuevo enfoque esté garantizado y el uso de nuevas herramientas caso dado esto). ¿Sería capaz de inyectar mi propia lógica cuando una condición no se cumple? ¡Realmente necesito mirar más en esto! – Clafou

+0

Me refiero a la lógica que me permitiría proporcionar una excepción útil y específica en lugar de un tipo de excepción genérico, lo que facilitaría a mi código de llamadas manejar los errores recuperables. – Clafou

+0

@Clafou, ¿qué rey de la lógica quieres inyectar? La violación del contrato trae a una 'ContractException'. Puedes manejarlo. – Dennis

Cuestiones relacionadas