Pergunta

Isto está relacionado com convenções usadas em C #.

Eu tenho um método que tem dois parâmetros (coordenadas X e Y). Essas coordenadas representam a posição na qual a "telha" pode residir. Se uma telha reside nestas coordenadas, o método retorna seu número. Se não reside azulejo nessas coordenadas, eu estou querendo saber como o método deve se comportar.

Eu vejo três opções:

  1. Usar exceções. I pode gerar uma exceção cada vez Método não encontra telha. No entanto, como esta situação não é rara, esta opção é o pior.
  2. Faça do jeito antiquado C ++ e retorno -1 se não há nenhuma telha.
  3. Faça o número telha um parâmetro de referência e alterar o tipo de retorno do método para booleano para mostrar se há uma telha ou não. Mas isso parece um pouco complicado para mim.

Então, o que devo fazer?

Foi útil?

Solução

retornar -1.

Este não é apenas uma convenção C ++, também é comum no .NET Framework - por exemplo, métodos como String.IndexOf ou imóveis como SelectedIndex para controles que representam listas.

Editar

Apenas para elaborar, das três opções na sua pergunta (Exception, o retorno -1, fora de parâmetros), retornando -1 é o caminho a percorrer. As exceções são para situações excepcionais e as diretrizes Microsoft codificação recomenda evitar os parâmetros sempre que possível.

No meu ponto de vista retornar -1 (desde que seja sempre vai ser um valor inválido), retornando um int anulável, ou retornar um objeto Tile são todas as soluções aceitáveis, e você deve escolher o que for mais consistente com o resto do seu aplicativo . Eu não posso imaginar qualquer desenvolvedor teria a menor dificuldade com qualquer um dos seguintes:

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 ...
}

Eu não tenho certeza eu entendo o comentário de Peter Ruderman sobre o uso de um int sendo "muito mais eficiente do que voltar um tipo anulável". Eu teria pensado que qualquer diferença seria insignificante.

Outras dicas

Você pode retornar nulo, e verificar isso no código de chamada.

Claro que você teria que usar um tipo anulável:

int? i = YourMethodHere(x, y);

As exceções são para casos excepcionais, portanto, usando exceções em um conhecido e esperado situação de erro é "mau". Você também são mais provável, agora, ter try-capturas em todos os lugares para lidar com esse erro especificamente porque você espera desta situação de erro acontecer.

Fazendo o seu valor de retorno de um parâmetro é aceitável se a sua única condição de erro (digamos -1) é confusable com um valor real. Se você pode ter um número telha negativa, então esta é a melhor maneira de ir.

A int anulável é uma alternativa possível a um parâmetro de referência, mas que está a criar objetos com este por isso, se um "erro" é uma rotina que você pode estar fazendo mais trabalho desta forma do que um parâmetro de referência. Como Roman apontou em um comentário em outro lugar você vai ter C questões # vs. VB com o tipo anulável sendo introduzidas tarde demais para VB para fornecer açúcar sintático agradável como C # tem.

Se suas telhas só pode ser não-negativo, em seguida, retornando -1 é uma forma aceitável e tradicional para indicar um erro. Seria também o menos caro em termos de desempenho e memória.


Outra coisa a considerar é a auto-documentação. Usando -1 e uma exceção são convenção: você teria de documentação escrita para se certificar de que o desenvolvedor está ciente deles. Usando um retorno int? ou um parâmetro de referência seria melhor auto-descrevem-se e que não requerem documentação para um desenvolvedor para saber como lidar com a situação de erro. É claro :) você deve sempre escrever a documentação, assim como a forma como você deve fio dental os dentes diariamente.

Use um valor de retorno nulo.

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

Esta é a solução mais clara.

Se o seu método tem acesso aos objetos de cerâmica subjacentes, outra possibilidade seria a de devolver o objeto em si azulejo, ou nulo, se não existe tal telha.

Eu iria com a opção 2. Você está certo, lançar uma exceção em um caso tão comum pode ser ruim para o desempenho, e usando um parâmetro de saída e retorno de um verdadeiro ou falso é útil, mas screwy para ler.

Além disso, pensar no método string.IndexOf(). Se nada for encontrado, ele retorna -1. Eu seguir esse exemplo.

Você poderia retornar -1, como é que uma abordagem bastante comum C #. No entanto, talvez seja melhor para realmente voltar a telha que foi clicado, e no caso em que nenhuma peça foi clicado, retornar uma referência a uma instância singleton NullTile. A vantagem de fazê-lo desta maneira é que você dá um significado concreto para cada valor retornado, ao invés de apenas ser um número que não tem nenhum significado intrínseco além do seu valor numérico. Um tipo 'NullTile' é muito específico quanto ao seu significado, deixando pouco a dúvida para outros leitores de seu código.

As melhores opções são para retornar um boolean tão bem ou nulo retorno.

por exemplo.

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

ou,

int? GetTile(int x, int y);

Existem várias razões para preferir o padrão "TryGetValue". Por um lado, ele retorna um booleano, então o código do cliente é incrivelmente simples, por exemplo: if (TryGetValue (fora someVal)) {/ * algum código * /}. Compare isso com o código do cliente que requer comparações valor de sentinela hard-coded (a -1, 0, null, pegando um determinado conjunto de exceções, etc.) "números mágicos" surgir rapidamente com os desenhos e factoring fora o tight-acoplamento torna-se uma tarefa árdua.

Quando os valores de sentinela, nula, ou exceções são esperados, é absolutamente vital que você verifique a documentação sobre qual mecanismo é usado. Se a documentação não existe ou não está acessível, um cenário comum, então você tem que inferir com base em outras evidências, se você fizer a escolha errada você simplesmente está se preparando para uma exceção nula-referência ou outros defeitos ruins. Considerando que, o padrão TryGetValue () é muito perto de auto-documentado por ele é nome e assinatura do método sozinho.

Eu tenho minha própria opinião sobre a pergunta que você pediu, mas é dito acima e Eu votei em conformidade.

Quanto à questão que você não pediu, ou pelo menos como uma extensão para todas as respostas acima: Eu seria a certeza de manter a solução para situações semelhantes consistentes em todo o aplicativo. Em outras palavras, qualquer resposta que você resolver sobre, mantenha-o mesmo dentro do aplicativo.

Se o método é parte de uma biblioteca de baixo nível, então o seu projeto padrão .NET provavelmente ditames que você lançar exceções a partir do seu método.

Esta é a forma como o .NET framework geralmente funciona. Seu interlocutor de nível superior deve pegar suas exceções.

No entanto, desde que você parece estar fazendo isso a partir de um segmento interface do usuário, que tem implicações de desempenho desde que você está respondendo a eventos de interface - Eu faço o que Jay Riggs já foi sugerido, return null, e certifique-se o seu interlocutor verificar se há um valor de retorno nulo .

Eu dividi-lo em dois métodos. Ter algo como CheckTileExists(x,y) e GetTile(x,y). Os ex-Retorna um booleano que indica se há ou não uma telha nas coordenadas indicadas. O segundo método é essencialmente o que você está falando em seu post original, exceto que ele deve lançar uma exceção quando dado coordenadas inválidos (desde que indica o chamador não o fez primeiro CheckTileExists() chamada, por isso é legitimamente uma situação excepcional. Para o causa da velocidade, você provavelmente quer estes dois métodos para compartilhar um cache, de modo que em caso eles são chamados um após o outro, a sobrecarga sobre a função GetTile() seria insignificante. Eu não sei se você já tem um objeto apropriado para colocar estes métodos em ou se talvez você deve torná-los dois métodos em uma nova classe. IMHO, a pena de esta abordagem desempenho é insignificante eo aumento da clareza código supera-lo.

É possível que você tenha criado (ou poderia criar) um objeto Tile que é referenciado nas coordenadas? Se assim for, você pode retornar uma referência para que a telha ou null se não houver azulejo nas coordenadas indicadas:

public Tile GetTile(int x, int y) {
    if (!TileExists(x, y)) 
        return null;
    // ... tile lookup here...
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top