2011-03-28 10 views
8

He creado una clase que analiza algún documento del archivo.Elegir entre la excepción y el valor de retorno

class Parser 
{ 
    public Parse(string fileName) 
    { 
    /// 
    } 
} 

A veces puede haber errores de análisis en ese caso analizador tiene para devolver ciertos datos. Creé una clase especial para eso.

class ParsingError 
{ 
// some data 
} 

¿Cómo puedo manejar estos errores correctamente? Tengo al menos dos opciones:

crear mi propia excepción o valor de retorno.

Opción uno

myParser.Parse(fileName, out error); 

Opción dos

try 
{ 
    myParser.Parse(fileName) 
} 

catch(MyParsingException ex) 
{ 
    // use ex.Error field 
} 

ACTUALIZACIÓN

Si no me equivoco la ideología detrás de la excepción es que debe ocuparse de algo excepcional, esa es una situación que el método no tiene la intención de tratar.

Esto me lleva a preguntarse si, por ejemplo:

el analizador encuentra campo desconocido en el archivo, o la codificación es incorrecto

habría que considerar un caso excepcional?

+0

cuestión de gustos? Las funciones del analizador que conozco en C# usan la excepción. – jwillmer

+0

posible duplicado de [.Valor de retorno neto frente a la pregunta de diseño de excepción lanzada] (http://stackoverflow.com/q/4884539/102112) – Alex

+0

¿Hay algo más en esta pregunta aparte de cuál es mejor? Esa pregunta se responde en varias preguntas, p. http://stackoverflow.com/questions/99683/which-and-why-do-you-prefer-exceptions-or-return-codes – StuperUser

Respuesta

14

Piense en lo típico que es tener un error de análisis. Si es típico, favor de un valor de retorno. Las excepciones se deben usar para cosas que no son normales.

+0

Buena respuesta. Todavía tengo una pregunta, sin embargo. ¿No está decidiendo qué tan típico depende de su juicio personal? De alguna manera se siente así. Por ejemplo, cuando intente convertir la cadena "asd" en un entero, se lanzará una excepción. ¿Podemos decir que no es típico a pesar de que este error es bastante común? –

+0

@Anar: en tales casos, normalmente tiene dos funciones distintas (o una con una bandera): una será "intente analizar y devolver un código de error" y la otra será "analizar y lanzar una excepción si hay algo" y la el segundo normalmente llamará al primero internamente y el desarrollador decidirá cuál usar. Utilizará el primero para tratar con la entrada del usuario y similares y el segundo para analizar algo que proviene de una fuente confiable. – sharptooth

+0

En este contexto, lo que tengo dificultades para entender es que ¿cómo se puede definir "_a fuente confiable_" para que se pueda usar Parse (no TryParse)? Lo que estoy tratando de decir es que esta cuestión confiable/no confiable es una cuestión de interpretación y nuestra interpretación puede ser, naturalmente, incorrecta. ¿Por qué el uso de excepciones o valores de retorno depende de nuestras interpretaciones de "podría ser falso"? –

1

Si su API dice que maneja los errores de análisis, entonces esta no es una situación excepcional y tal vez se deben devolver los errores de análisis. Para otras cosas, como archivos perdidos, archivos bloqueados, entrada no válida (que no sea el análisis dudoso), debe lanzar excepciones.

3

Me gustaría ir con la opción tres

ParseResult result = myParser.Parse(filename) 

Aquí ParseResult puede proporcionar más detalles sobre el resultado del análisis, tanto positivos como negativos.

Si la condición de falla es muy rara y se consideraría un resultado inesperado, entonces elegiría la opción dos y lanzaría una excepción. Por supuesto, la solución final podría ser una combinación, donde los errores comunes se devuelven en el ParseResult, pero las condiciones excepcionales como la falla al abrir el archivo, etc. aparecen como excepciones.

0

Para mí, depende de cómo planeo consumir el error y qué tipo de error es. El contexto del método también juega un papel. Si se espera que el método llegue a un error en el xml de vez en cuando, bueno, entonces no es una excepción en mi opinión, y debería tratarse de acuerdo con esto.

Digamos que estoy escribiendo un validador XML, y luego devolver un error es el camino a seguir. Si estoy escribiendo un analizador de configuración XML, una excepción parece más apropiada.

2

Eso depende de si MyParsingException es solo una clase derivada de System.Exeption, o si contiene información adicional sobre lo que salió mal al intentar analizar el archivo. Si no existe tal información, entonces creo que el método Parse debe devolver tal vez una cadena, o NULL si ocurre un error:

public string Parse(string fileName) 
{ 
    string res = null; 
    try 
    { 
     /// parse the file, assign parse result to res 
    } 
    catch 
    { 
     res = null; 
    } 
    return res; 
} 

o, si la excepcion es muy servicial, contiene información sobre el archivo (nombre), número de línea, etc ...: filosofía

public string Parse(string fileName) 
{ 
    string res = null; 
    int errorLine = -1; 
    try 
    { 
     // foreach line of text to parse -- errorLine = lineNumber; 
     /// parse the file, assign parse result to res 
    } 
    catch (Exeption ex) 
    { 
     MyParsingException myEx= new MyParsingException ("parsing error", ex); 
     myEx.Data["fileName"] = fileName; 
     myEx.data["lineNumber"] = errorLine ; 
     throw myEx; 
    } 
    return res; 
} 
// then you can have some really useful info: 

try 
{ 
    myParser.Parse(fileName) 
} 
catch(MyParsingException ex) 
{ 
    // use ex.Data to get the "fileName" and "lineNumber" properties. 
} 
5

.NET de tierra sobre las excepciones es un poco diferente a otras plataformas. No pasa mucho tiempo en .NET land para darte cuenta de que ya no estás en OZ, y que las excepciones se lanzan con frecuencia.

De MSDN en .NET 4: No devuelva los códigos de error. Las excepciones son el principal medio para informar errores en los marcos.

De MSDN en .NET 4.5: Una excepción es cualquier condición de error o comportamiento inesperado que se encuentra en un programa en ejecución.

Un ejemplo que dan es si un cliente no puede conectarse a un punto final. Por lo tanto, si considera que a veces los sitios web no están disponibles para redes u otras razones, que no se ajustan a la definición tradicional de "excepcional", puede hacerse una idea de cómo piensan los creadores que se utilicen las excepciones.

+0

Se debe agregar la segunda parte de la declaración de MSDN en .NET 4.5: "Se pueden generar excepciones debido a un error en el código o en el código al que se llama (como una biblioteca compartida), ...", lo que significa que ** Las excepciones son para fallas de código, no para fallas de datos **. – Lightman

2

Los indicadores de error o valores devueltos son generalmente mejores en los casos en que el llamante inmediato va a tratar la condición no válida. Las excepciones son generalmente mejores en los casos en que habrá muchas llamadas a funciones que podrían fallar de una manera particular, y el manejo de fallas para todas esas llamadas a funciones debería ser idéntico.

A menudo, el autor de un método no puede saber qué escenario se aplicará a sus llamadores (de hecho, es común que algunos llamantes se ajusten mejor a un patrón y algunos al otro). forma preferida de Microsoft de manejar esto es usar el patrón:

Thing GetThing(int param1, string param2); 
bool TryGetThing(int param1, string param2, out Thing result); 

eso es ciertamente un concepto mejor que confinar las personas que llaman para adaptarse a un patrón o la otra, aunque no me gusta la implementación particular. Microsoft recomienda explícitamente el uso de métodos separados, en lugar de usar un método con un parámetro que indique si una falla arrojaría una excepción, pero esa filosofía tiene un costo: significa que si uno de los pasos de GetThing o TryGetThing se puede hacer con un El método "do" o "try", el código para GetThing y TryGetThing tendrá que duplicarse en gran medida, con uno que llama a los métodos "do" y el otro que llama a los métodos "try".

Un enfoque alternativo sería tener un delegado o un objeto de tipo interfaz que indique qué debería hacer un método "try" si ocurre una excepción. Por ejemplo, uno podría tener una función:

Thing TryGetThing(int param1, string param2, bool ThrowOnError, out ErrorInfo errInf); 

posiblemente con una sobrecarga, que, si se omiten los dos últimos parámetros, llama a voluntad lo anterior con true para ThrowOnError, y una variable ficticia para errInf. Si los métodos utilizados por TryGetThing siguen un patrón similar, es posible que pueda llamarlos sin tener que duplicar el código para los casos de prueba/do.

Cuestiones relacionadas