Pregunta

Esto se relaciona con las convenciones utilizadas en C #.

Tengo un método que tiene dos parámetros (coordenadas X e Y). Estas coordenadas representan la posición en la que un "mosaico" puede residir. Si una baldosa reside en estas coordenadas, el método devuelve su número. Si no hay baldosas reside en estas coordenadas, me pregunto cómo el método debe comportarse.

veo tres opciones:

  1. Use excepciones. Puedo lanzar una excepción cada vez que el método no encuentra ninguna baldosa. Sin embargo, ya que esta situación no es rara, esta opción es la peor de todas.
  2. Hacerlo de la antigua C ++ camino y devolver -1 si no hay un azulejo.
  3. Marca el número de baldosas de un parámetro de referencia y cambiar el tipo de retorno del método a booleano para indicar si hay un azulejo o no. Pero esto parece un poco complicado para mí.

Entonces, ¿qué debería hacer?

¿Fue útil?

Solución

Vuelta -1.

Esto no es sólo convención un C ++, también es común en el .NET Framework - por ejemplo, métodos como String.IndexOf o propiedades como SelectedIndex para los controles que representan listas.

Editar

Sólo para elaborar, de las tres opciones en su pregunta (Excepción, devuelve -1, fuera de parámetros), devolviendo -1 es el camino a seguir. Las excepciones son para situaciones excepcionales, y la codificación de pautas Microsoft recomienda evitar en lo posible a cabo parámetros.

A mi devolviendo -1 (siempre que siempre va a ser un valor no válido), que devuelve un int anulable, o devolver un objeto del azulejo son todas las soluciones aceptables, y usted debe elegir la que sea más coherente con el resto de su aplicación . No me puedo imaginar cualquier desarrollador tendría la menor dificultad con cualquiera de los siguientes:

int tileNumber = GetTile(x,y);
if  (tileNumber != -1)
{
   ... use tileNumber ...
}


int? result = GetTile(x,y);
if (result.HasValue)
{
    int tileNumber = result.Value; 
   ... use tileNumber ...
}


Tile tile = GetTile(x,y);
if (tile != null)
{
   ... use tile ...
}

No estoy seguro de entender el comentario de Peter Ruderman sobre el uso de un int ser "mucho más eficiente que devolver un tipo anulable". Yo habría pensado alguna diferencia sería insignificante.

Otros consejos

Puede devolver null, y comprobar si esta en el código de llamada.

Por supuesto que tendría que utilizar un tipo anulable:

int? i = YourMethodHere(x, y);

Las excepciones son los casos de excepción, por lo que el uso de excepciones en un conocidos y esperada situación de error es "malo". También es más probable, ahora, para tener Try-capturas en todas partes para controlar este error específicamente porque esperas esta situación de error que ocurra.

La fabricación de su valor de retorno es un parámetro aceptable si su condición de error solamente (por ejemplo -1) es confundible con un valor real. Si usted puede tener un número de baldosas negativo entonces este es un mejor camino a seguir.

Un int anulable es una alternativa posible a un parámetro de referencia, sino que está creando objetos con este por lo que si un "error" es la rutina que se le puede hacer más trabajo de esta manera que un parámetro de referencia. Como Romano señaló en un comentario en otro lugar que tendrá C # vs. problemas con VB el tipo anulable está introduciendo demasiado tarde para VB para proporcionar el azúcar sintáctica agradable como C # tiene.

Si las fichas sólo pueden ser no negativo luego regresar -1 es una forma aceptable y tradicional para indicar un error. También sería el menos costoso en términos de rendimiento y la memoria.


Otra cosa a considerar es la auto-documentación. Uso de -1 y una excepción son convención: tendría que escribir la documentación para asegurarse de que el desarrollador es consciente de ellos. El uso de un retorno int? o un parámetro de referencia sería mejor auto-describirse a sí misma y no haría requerir documentación para un desarrollador para saber cómo manejar la situación de error. Por supuesto :) siempre se debe escribir la documentación, al igual que cómo se debe usar el hilo dental todos los días.

Utilice un valor de retorno anulable.

int? GetTile(int x, int y) {
   if (...)
      return SomeValue;
   else
      return null;
}

Esta es la solución más clara.

Si su método tiene acceso a los objetos de tejas subyacentes, otra posibilidad sería la de devolver el objeto en sí mismo azulejo, o null si no hay tal azulejo.

Me gustaría ir con la opción 2. Tienes razón, lanzar una excepción en tal caso común puede ser perjudicial para el rendimiento y el uso de un parámetro de salida y devolver un verdadero o falso es útil, pero chiflado de leer.

Además, pensar en el método string.IndexOf(). Si no se encuentra nada, devuelve -1. Me seguir ese ejemplo.

Se puede devolver -1, ya que es un enfoque bastante común # C. Sin embargo, podría ser mejor para volver realidad la baldosa que se hizo clic, y en el caso de que no se ha hecho clic azulejo, devolver una referencia a una instancia de NullTile Singleton. La ventaja de hacerlo de esta manera es que le da un significado concreto para cada valor devuelto, en lugar de simplemente ser un número que no tiene ningún significado intrínseco más allá de su valor numérico. Un tipo 'NullTile' es muy específico en cuanto a su significado, dejando poco a dudar de otros lectores de su código.

Las mejores opciones son para devolver un valor lógico tan bien o devolver null.

por ejemplo.

bool TryGetTile(int x, int y, out int tile);

o

int? GetTile(int x, int y);

Hay varias razones para preferir el patrón "TryGetValue". Por un lado, devuelve un valor lógico, por lo que el código de cliente es muy sencillo, por ejemplo: si (TryGetValue (fuera someVal)) {/ * algún código * /}. Compare esto con código de cliente que requiere comparaciones de valor centinela no modificables (a -1, 0, null, la captura de un conjunto particular de excepciones, etc.) "números mágicos" surgen rápidamente con esos diseños y factorizar el apretado-acoplamiento se convierte una tarea.

Cuando se espera que los valores centinela, nula, o excepciones que es absolutamente vital que compruebe la documentación en la que se utiliza el mecanismo. Si la documentación no existe o no es accesible, un escenario común, entonces usted tiene que inferir sobre la base de otras pruebas, si se hace la elección equivocada simplemente está preparando para una excepción nula referencia u otros defectos malas. Mientras que, el TryGetValue () patrón es bastante cerca de auto-documentado por su nombre y la firma del método solo.

Tengo mi propia opinión sobre la cuestión que se le pide, pero ha dicho anteriormente y he votado en consecuencia.

En cuanto a la pregunta que usted no pidió, o al menos como una extensión a todas las respuestas anteriores: Me gustaría estar seguro de mantener la solución a situaciones similares consistentes a través de la aplicación. En otras palabras, cualquier respuesta que se asientan en, mantener el mismo dentro de la aplicación.

Si el método es parte de una biblioteca de nivel bajo, entonces su diseño estándar .NET probablemente dicta que lanzar excepciones de su método.

Esta es la forma del marco .NET generalmente funciona. Las personas que llaman de alto nivel deben coger sus excepciones.

Sin embargo ya que parece estar haciendo esto desde un hilo de interfaz de usuario, lo que tiene consecuencias en el rendimiento, ya que está respondiendo a los eventos de interfaz de usuario - hago lo que Jay Riggs ya se ha sugerido, regrese nula, y asegúrese de que las personas que llaman comprobar un valor devuelto nulo .

Me dividirlo en dos métodos. Tener algo como CheckTileExists(x,y) y GetTile(x,y). El primero devuelve un valor booleano que indica si hay o no un azulejo en las coordenadas dadas. El segundo método es esencialmente el que usted está hablando en su puesto original, excepto que debe lanzar una excepción cuando se les da las coordenadas no válidas (puesto que indica la persona que llama no lo hizo primero CheckTileExists() llamada, por lo que es legítimamente una situación excepcional. Para el aras de la rapidez, lo que probablemente quiere que estos dos métodos para compartir una memoria caché, por lo que en caso de que se llaman uno tras otro, la sobrecarga de la función GetTile() sería insignificante. no sé si ya tiene un objeto adecuado para poner estos métodos en o si tal vez debería hacer que dos métodos en una nueva clase. en mi humilde opinión, la penalización en el rendimiento de este enfoque es insignificante y el aumento de la claridad del código es mucho mayor que ella.

¿Es posible que ha creado (o podría crear) un objeto Tile que se hace referencia en las coordenadas? Si es así, puede devolver una referencia a esa baldosa o null si no hay baldosas en las coordenadas dadas:

public Tile GetTile(int x, int y) {
    if (!TileExists(x, y)) 
        return null;
    // ... tile lookup here...
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top