¿Por qué utilizar la manipulación de código aparentemente “seguro” excepción?

StackOverflow https://stackoverflow.com/questions/1894983

  •  19-09-2019
  •  | 
  •  

Pregunta

Por favor, alguien me puede explicar, lo que puede provocar una excepción en este código?

function CreateBibleNames: TStrings;
begin
  Result := TStringList.Create;
  try
    Result.Add('Adam');
    Result.Add('Eva');
    Result.Add('Kain');
    Result.Add('Abel');
  except
    Result.Free;
    raise;
  end;      
end;
excepción

Desde que uso delphi He utilizado la manipulación quizás una vez. Considero que el código anterior para ser escrito por un programador skillfull y no creo que las excepciones son redundantes. Pero aún así, mediante el manejo de excepciones en este concepto sigue siendo un misterio para mí. Parece que es un código de seguridad (sin tratar, salvo final). He visto muchas veces fragmentos de código similar como esto, por eso es probable que haya una buena razón para escribir de esta manera, a pesar de mi experiencia, eso no prueba que ésta sea la necesidad.

Por otra parte, cuando algo falla, consigo descripción de excepción ....

Gracias

¿Fue útil?

Solución

De acuerdo, ese código es extraño, estoy de acuerdo, y entiendo totalmente por qué se quedó escrito de esa manera. Pero fue escrito de esa manera porque la premisa subyacente en el código es incorrecto. El hecho de que la construcción parece extraño debe ser un "olor código", y se debe decir que hay algo que no puede ser que consiga hacer la mejor manera posible.

En primer lugar, he aquí por qué la construcción inusual en el bloque try ... except. La función crea un TStringList, pero si algo va mal en las operaciones de llenado, entonces el TStringList que se creó se "perdió" a cabo en el montón y será una pérdida de memoria. Por lo que el programador original era defensiva y se aseguró de que si se produce una excepción, la TStringList sería liberado y luego la excepción conseguiría levantado de nuevo.

Ahora aquí está la parte "mala premisa". La función devuelve una instancia de TStrings. Esto no es siempre la mejor manera de hacer esto. Volviendo una instancia de un objeto como que plantea la pregunta "¿Quién va a disponer de esta cosa que he creado?". Se crea una situación en la que podría ser fácil - en el lado llamante - olvidar que una instancia TStrings ha sido asignado.

A "Mejor Práctica" aquí es tener la función de tomar una TStrings como un parámetro, y luego rellenar la instancia existente. De esta manera, no hay ninguna duda acerca de quién es el propietario de la instancia (la persona que llama) y, por tanto, que debe gestionar su tiempo de vida.

Por lo tanto, la función se convierte en un procedimiento y podría tener este aspecto:

procedure CreateBibleNames(aStrings: TStrings);
begin
  if aStrings <> nil then
  begin
    aStrings .Add('Adam');
    aStrings .Add('Eva');
    aStrings .Add('Kain');
    aStrings .Add('Abel');
  end;      
end;

Ahora bien, esto no quiere decir que la devolución de una instancia de objeto es una mala cosa cada vez - que es la única función del patrón de fábrica muy útil, por ejemplo. Pero para más funciones "generales" de este tipo, lo anterior es una "mejor" forma de hacer las cosas.

Otros consejos

Es una buena costumbre de estar en al devolver objetos recién construidas a partir de funciones. En un escenario más complejo que una lista de cadenas, algunos invariantes podría ser roto o se produce otro error, y por lo tanto una excepción, y en ese caso desea que el valor de retorno liberado. En lugar de tener que examinar todas las situaciones posibles cuando esto puede ocurrir, por lo general es una buena práctica tener un patrón único para el retorno de los objetos de nueva construcción y seguirlo por todas partes.

De este modo, cuando la aplicación de los objetos que está construyendo los cambios en el futuro, que está todavía seguro si llegan a lanzar una excepción.

La única razón por la posibilidad de una excepción que puedo ver es una excepción OutOfMemory y si este es el caso - todas las apuestas están fuera de todos modos. En mi opinión, esto es un ejemplo de utilización abusiva de un concepto válido.

El uso excesivo e injustificado de la prueba, excepto desordena el código y lo hace más difícil de leer

Me gustaría escribir el código de esa manera, por varias razones:

1) Mediante la estandarización de cómo se ven las asignaciones de memoria, es fácil de inspeccionar el código fuente para ver si falta algo, sin tener que leer todas las líneas. Aquí, simplemente ver el .Create, y darse cuenta de que el manejo de excepciones es bueno, por lo que no tiene que leer la parte entre try ... except.

2) Al estandarizar la forma de un mejor código asignaciones de memoria, nunca se olvida de hacerlo, aun cuando sea necesario.

3) Si más adelante cambiar el código fuente, inserte un código, cambiar cómo funciona .Add, reemplace TStringList con otra cosa, etc., entonces no sería romper este código.

4) Esto significa que usted no tiene que pensar si TStringList.Add () será lanzar excepciones, o no, el alivio de su cerebro para otros trabajos que proporciona más valor.

La excepción más obvia sería lo Delphi utiliza para efectuar una OutOfMemoryException. Si no hay memoria suficiente para agregar un par de cadenas a una lista, liberar toda la lista y volver a emitir la excepción.

Esto parece demasiado defensivo de programación para hacer una lista de nombres predeterminados -. Por lo general, si se obtiene una excepción debido a estar fuera de la memoria, toda la aplicación se riega

Sin la fuente de TStringList, o documentación autorizada, realmente no se puede saber. Sólo con fines ilustrativos, supongamos que TStringList está escrito de tal manera que cuando la memoria se estrecha, se inicia el intercambio de partes de la lista y de disco, lo que permite administrar una lista tan grande como su disco. Ahora la persona que llama es también susceptible a la gama de errores de E / S:. Sin espacio en disco, bloque defectuoso encontrado, tiempo de espera de la red, etc.

es el manejo de tales excepciones exageración? cuestión de criterio basado en escenario. Podríamos preguntar a los programadores de la NASA lo que piensan.

Ese tipo de código es un modelo clásico "de fábrica". Ese ejemplo es trivial, y puede no requerir el manejo de excepciones, ya que podría provocar excepciones en casos de esquina extremas. Pero si el código de fábrica es mucho más complejo, es correcto para liberar la instancia creada antes de volver a poner ninguna excepción encontrado debido a que la persona que llama no puede saber si la instancia se creó o no antes de que la excepción era elevado. Es mucho mejor para asumir la instancia no fue creada o liberado si no se devuelve ninguna excepción. Las fábricas son útiles cuando la instancia devuelto puede no ser siempre el mismo (es decir, cualquier clase en una jerarquía dada), y cuando los parámetros para crear la instancia son "unknonwn" a la persona que llama pero no la fábrica. En tales casos, la persona que llama no puede pasar una instancia ya creado sólo para ser "llenado" con los parámetros adecuados, pero sólo ha de requerir una instancia - por supuesto que tiene que ser clara la persona que llama se convierte en el "dueño" de la instancia creada .

Como una nota interesante, algunos de los autores de Java ahora consideran que la decisión de exigir la captura de excepciones en prácticamente todos los casos que ser un error. Eso es porque la mayoría de las excepciones realmente resultan en el programa siendo asesinados, por lo que también podría permitir que el sistema de ejecución de matar el programa e imprimir un seguimiento de la pila, en lugar de obligar al programador a detectar la excepción y ... bueno, simplemente imprimir algo y matar el programa.

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