Pergunta

Eu não entendo quando um parâmetro de saída deve ser usado, eu, pessoalmente, enrole o resultado em um novo tipo se eu precisar voltar mais do que um tipo, acho que muito mais fácil de trabalhar do que fora.

Eu tenho visto método como este,

   public void Do(int arg1, int arg2, out int result)

há casos em que realmente faz sentido?

como sobre TryParse, por que não voltar um ParseResult tipo?ou o mais recente quadro retornar um valor nulo-capaz de escrever?

Foi útil?

Solução

Fora é bom quando você tem um TryNNN função e fica claro que o parâmetro externo sempre será definido, mesmo que a função não tenha sucesso. Isso permite que você confie no fato de que a variável local que você declarar será definida, em vez de precisar fazer verificações posteriormente no seu código contra o NULL. (Um comentário abaixo indica que o parâmetro pode ser definido como null, portanto, você pode verificar a documentação para a função que você está chamando para ter certeza se é esse o caso ou não.) Isso torna o código um pouco mais claro e mais fácil de ler. Outro caso é quando você precisa retornar alguns dados e um status na condição do método como:

public bool DoSomething(int arg1, out string result);

Nesse caso, o retorno pode indicar se a função foi bem -sucedida e o resultado é armazenado no parâmetro out. É certo que este exemplo é artificial porque você pode projetar uma maneira de a função simplesmente retornar um string, mas você entendeu a ideia.

Uma desvantagem é que você deve declarar uma variável local para usá -las:

string result;
if (DoSomething(5, out result))
    UpdateWithResult(result);

Ao invés de:

UpdateWithResult(DoSomething(5));

No entanto, isso pode nem ser uma desvantagem, depende do design que você está buscando. No caso do DateTime, ambos os meios (Parse e TryParse) são fornecidos.

Outras dicas

Bem como na maioria das coisas, depende. Vejamos as opções

  • você pode retornar o que quiser como o valor de retorno da função
  • Se você deseja retornar vários valores ou a função já possui um valor de retorno, você pode usar params ou criar um novo tipo composto que expõe todos esses valores como propriedades

No caso do Tryparse, o uso de um parâmetro out é eficiente - você não precisa criar um novo tipo que seja 16b de sobrecarga (em máquinas 32b) ou incorrer no custo do perf de que eles coletavam o lixo após a chamada. O TryParse pode ser chamado de dentro de um loop, por exemplo - a regra dos parâmetros de saída aqui.
Para funções que não seriam chamadas dentro de um loop (ou seja, o desempenho não é uma grande preocupação), o retorno de um único objeto composto pode ser 'mais limpo' (subjetivo ao espectador). Agora com tipos anônimos E digitação dinâmica, pode se tornar ainda mais fácil.

Observação:

  1. out Os parâmetros têm algumas regras que precisam ser seguidas, ou seja, o compilador garantirá que a função inicialize o valor antes de sair. Portanto, o TryParse precisa definir o parâmetro para algum valor, mesmo que a operação de análise falhasse
  2. O padrão Tryxxx é um bom exemplo de quando usar os parâmetros - int32.TryParse foi introduzido porque as pessoas reclamaram do sucesso do perfume de exceções para saber se o Parse falhou. Além disso, a coisa mais provável que você faria no caso de Parse ter sucesso é obter o valor analisado - usando um parâmetro de saída significa que você não precisa fazer outra chamada de método para analisar

Eu acho que é útil para situações em que você precisa devolver um booleano e um valor, como TryParse, mas seria bom se o compilador permitir algo assim:

bool isValid = int.TryParse("100", out int result = 0);

Definitivamente, os parâmetros de saída são destinados a ser usado quando você tem um método que deve retornar mais de um valor, no exemplo que você postou:

public void Do(int arg1, int arg2, out int result)

Não faz muito sentido usar um parâmetro de saída, pois você está apenas retornar um valor, e que o método poderia ser usado melhor, se você remover o parâmetro de saída e pôr um int valor de retorno:

public int Do(int arg1, int arg2)

Há algumas coisas boas sobre parâmetros de saída:

  1. Parâmetros de saída são inicialmente consideradas não atribuídos.
    • Cada parâmetro de saída deve ser definitivamente atribuída antes do retorno do método, o código não irá compilar se você perder uma atribuição.

Em conclusão, eu, basicamente, tentar usar params na minha API privada para evitar a criação de tipos separados para quebrar vários valores de retorno, e no meu API pública, eu só usá-los em métodos que correspondem com o TryParse padrão.

Anos de atraso com uma resposta, eu sei.(e ref) é também muito útil se você não desejar que o seu método de fazer instanciar um novo objeto para retornar.Isto é muito relevante em sistemas de alto desempenho de onde você quer alcançar sub microssegundo desempenho para o seu método.instanciar é relativamente caro visto a partir de uma memória de acesso perspectiva.

Criar um tipo apenas para retornar valores parece pouco doloroso para mim :-) Primeiro terei que criar um tipo para retornar o valor e depois no método de chamada que atribuí o valor do tipo retornado à variável real que precisa.

Os parâmetros de saída são Simipler para usar.

Sim, faz sentido. Veja isso, por exemplo.

String strNum = "-1";
Int32 outNum;

if (Int32.TryParse(strNum, out outNum)) {
    // success
}
else {
    // fail
}

O que você poderia retornar se a operação falhou em uma função normal com um valor de retorno? Você certamente não poderia retornar -1 para representar uma falha, porque não haveria diferenciação entre o valor de retorno de falha e o valor real que estava sendo analisado para começar. É por isso que retornamos um valor booleano para ver se foi bem -sucedido e, se o fizesse, já temos nosso valor de "retorno" com segurança.

Isso me incomoda que eu não possa passar nulo para o parâmetro out para as funções Tryparse.

Ainda assim, prefiro em alguns casos devolver um novo tipo com dois dados. Especialmente quando não estão relacionados, na maior parte ou uma peça, é necessária apenas para uma única operação um momento depois. Quando preciso salvar o valor resultante de uma função TryParse, gosto muito de ter um parâmetro fora, em vez de uma classe de resulta aleatória e com a qual tenho que lidar.

Se você sempre cria um tipo e, em seguida, você pode acabar com um monte de lixo na sua aplicação.

Como disse aqui, um caso de uso típico é um TrySomething Método onde você deseja retornar um booleano como um indicador para o sucesso e, em seguida, o valor real.Eu também acho que um pouco mais limpa em uma declaração if - todas as três opções tem aproximadamente o mesmo LOC de qualquer maneira.

int myoutvalue;
if(int.TryParse("213",out myoutvalue){
    DoSomethingWith(myoutvalue);
}

vs.

ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
    DoSomethingWith(myoutvalue.Value);
}

vs.

int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
    DoSomethingWith(myoutvalue.Value);
}

Como para o "Por que não retornar um Tipo Anulável":TryParse existe desde o Quadro 1.x, enquanto que os Tipos Anuláveis veio com 2.0 (pois eles necessitam de medicamentos Genéricos).Então, por que unneccessarily quebra de compatibilidade ou de iniciar a introdução de inconsistências entre TryParse em alguns tipos?Você sempre pode escrever o seu próprio Método de extensão para duplicar a funcionalidade já existente (Ver Eric Lipperts Post em um assunto não relacionado que inclui alguns raciocínio por trás de fazer/não fazer as coisas)

Outro caso é se você tiver que retornar vários valores não relacionados, mesmo que se você fizer o que deve disparar um alarme que seu método é a possibilidade de fazer muito.Por outro lado, se o Método é parecido com o de um cara de banco de dados ou serviço da web, chamada e você deseja armazenar em cache o resultado, pode fazer sentido para fazer isso.Claro, você poderia criar um tipo, mas, novamente, isso significa que mais um tipo em seu aplicativo.

Eu uso fora parâmetros, por vezes, para facilitar a leitura, ao ler o nome do método é mais importante do que qualquer que seja o resultado do método é, particularmente para os métodos que executam comandos, além de retornar os resultados.

StatusInfo a, b, c;

Initialize(out a);
Validate(a, out b);
Process(b, out c);

vs.

StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);

Pelo menos para mim, eu coloquei um monte de ênfase sobre os primeiros caracteres de cada linha quando estou a digitalização.Eu posso facilmente dizer o que está acontecendo no primeiro exemplo, depois de admitir que alguns "StatusInfo" as variáveis são declaradas.No segundo exemplo, a primeira coisa que eu vejo é que um monte de StatusInfo é recuperado.Eu tenho que digitalizar uma segunda vez para ver que tipo de efeitos os métodos podem ter.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top