Se queremos obter um valor de um método, podemos usar um valor de retorno, como este:
public int GetValue();
ou:
public void GetValue(out int x);
Eu realmente não entendo as diferenças entre eles e, portanto, não sei o que é melhor. Você pode me explicar isso?
Obrigado.
Tuple
se quiser, mas o consenso geral é que, se você precisar retornar mais de uma coisa, as coisas geralmente estão relacionadas de alguma forma e essa relação geralmente é melhor expressa como uma classe.return Tuple.Create(x, y, z);
não é tão feio. Além disso, é tarde para que eles sejam introduzidos no nível do idioma. O motivo de eu não criar uma classe para retornar valores de um parâmetro ref / out é porque os parâmetros ref / out realmente fazem sentido para grandes estruturas mutáveis (como matrizes) ou valores opcionais, e o último é discutível.Tuple<>
e C # tuplas !. Eu apenas desejei que o C # permitisse o retorno de tipos anônimos a partir de métodos com tipo deauto
dedução do compilador (como em Dlang).Respostas:
Os valores de retorno quase sempre são a escolha certa quando o método não tem mais nada para retornar. (Na verdade, eu não consigo pensar em quaisquer casos onde eu nunca querem um método vazio com um
out
parâmetro, se eu tivesse a escolha. C # 7 deDeconstruct
métodos para a desconstrução apoiada em língua atua como um muito, muito rara exceção a esta regra .)Além de qualquer outra coisa, impede o chamador de declarar a variável separadamente:
vs
Os valores de saída também impedem o encadeamento de métodos como este:
(De fato, esse também é um dos problemas com os configuradores de propriedades, e é por isso que o padrão do construtor usa métodos que retornam o construtor, por exemplo
myStringBuilder.Append(xxx).Append(yyy)
.)Além disso, os parâmetros de saída são um pouco mais difíceis de usar com reflexão e geralmente tornam os testes mais difíceis também. (Geralmente, mais esforço é feito para facilitar a simulação de valores de retorno do que parâmetros fora). Basicamente, não há nada que eu possa pensar que eles facilitem ...
Retorna valores FTW.
EDIT: Em termos do que está acontecendo ...
Basicamente, quando você passa um argumento para um parâmetro "out", precisa passar uma variável. (Os elementos de matriz também são classificados como variáveis.) O método que você chama não possui uma variável "nova" em sua pilha para o parâmetro - ele usa sua variável para armazenamento. Quaisquer alterações na variável são imediatamente visíveis. Aqui está um exemplo mostrando a diferença:
Resultados:
A diferença está na etapa "pós" - ou seja, após a variável ou parâmetro local ter sido alterado. No teste ReturnValue, isso não faz diferença para a
value
variável estática . No teste OutParameter, avalue
variável é alterada pela linhatmp = 10;
fonte
Dictionary.TryGetValue
é aplicável aqui, pois não é um método nulo. Você pode explicar por que deseja um parâmetro em vez de um valor de retorno? (Mesmo para , eu prefiro um valor de retorno que contém todas as informações de saída, pessoalmente Veja NodaTime de. Para um exemplo de como eu teria projetou.)out
TryGetValue
ParseResult<T>
out
parâmetro, você simplesmente não pode fazer nada com o valor.O que é melhor, depende da sua situação particular. Um dos motivos
out
existe é facilitar o retorno de vários valores de uma chamada de método:Portanto, um não é, por definição, melhor que o outro. Mas geralmente você deseja usar um retorno simples, a menos que tenha a situação acima, por exemplo.
EDIT: este é um exemplo que demonstra uma das razões pelas quais a palavra-chave existe. O exposto acima não deve ser considerado uma prática recomendada.
fonte
Geralmente, você deve preferir um valor de retorno a um parâmetro de saída. Parâmetros externos são um mal necessário se você se encontra escrevendo um código que precisa fazer duas coisas. Um bom exemplo disso é o padrão Try (como Int32.TryParse).
Vamos considerar o que o chamador dos seus dois métodos teria que fazer. Para o primeiro exemplo, eu posso escrever isso ...
Observe que eu posso declarar uma variável e atribuí-la através do seu método em uma linha. No segundo exemplo, fica assim ...
Agora sou forçado a declarar minha variável antecipadamente e escrever meu código em duas linhas.
atualizar
Um bom lugar para procurar ao fazer esses tipos de pergunta é o .NET Framework Design Guidelines. Se você possui a versão em livro, pode ver as anotações de Anders Hejlsberg e outras pessoas sobre esse assunto (página 184-185), mas a versão on-line está aqui ...
http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx
Se você precisar retornar duas coisas de uma API, agrupá-las em uma struct / classe seria melhor do que um parâmetro externo.
fonte
Há uma razão para usar um
out
parâmetro que ainda não foi mencionado: o método de chamada é obrigado a recebê-lo. Se o seu método produz um valor que o chamador não deve descartar,out
obriga o chamador a aceitá-lo especificamente:É claro que o chamador ainda pode ignorar o valor em um
out
parâmetro, mas você chamou a atenção dele.Essa é uma necessidade rara; com mais freqüência, você deve usar uma exceção para um problema genuíno ou retornar um objeto com informações de estado para um "FYI", mas pode haver circunstâncias em que isso é importante.
fonte
É preferência principalmente
Prefiro devoluções e se você tiver várias devoluções, poderá envolvê-las em um resultado DTO
fonte
Você pode ter apenas um valor de retorno enquanto pode ter vários parâmetros de saída.
Você só precisa considerar parâmetros nesses casos.
No entanto, se você precisar retornar mais de um parâmetro do seu método, provavelmente desejará examinar o que está retornando de uma abordagem OO e considerar se é melhor retornar um objeto ou uma estrutura com esses parâmetros. Portanto, você voltou a um valor de retorno novamente.
fonte
Você quase sempre deve usar um valor de retorno. '
out
' parâmetros criam um pouco de atrito para muitas APIs, composicionalidade etc.A exceção mais notável que vem à mente é quando você deseja retornar vários valores (o .Net Framework não possui tuplas até 4.0), como no
TryParse
padrão.fonte
Eu preferiria o seguinte em vez de qualquer um desses exemplos simples.
Mas, eles são todos iguais. Normalmente, só seria usado 'out' se eles precisassem passar vários valores de volta do método. Se você deseja enviar um valor dentro e fora do método, escolha-se 'ref'. Meu método é o melhor, se você está retornando apenas um valor, mas se deseja passar um parâmetro e recuperar um valor, provavelmente você escolheria sua primeira opção.
fonte
Eu acho que um dos poucos cenários em que seria útil seria ao trabalhar com memória não gerenciada, e você deseja deixar óbvio que o valor "retornado" deve ser descartado manualmente, em vez de esperar que seja descartado por conta própria .
fonte
Além disso, os valores de retorno são compatíveis com os paradigmas de design assíncrono.
Você não pode designar uma função "assíncrona" se ela usar parâmetros ref ou out.
Em resumo, os valores de retorno permitem o encadeamento de métodos, uma sintaxe mais limpa (eliminando a necessidade de o chamador declarar variáveis adicionais) e permitem designs assíncronos sem a necessidade de modificações substanciais no futuro.
fonte
Ambos têm um propósito diferente e não são tratados da mesma forma pelo compilador. Se seu método precisar retornar um valor, você deverá usar return. Out é usado onde seu método precisa retornar vários valores.
Se você usar return, os dados serão gravados primeiro na pilha de métodos e depois nos métodos de chamada. Enquanto no caso de fora, ele é gravado diretamente na pilha de métodos de chamada. Não tenho certeza se existem mais diferenças.
fonte
Como outros já disseram: retorne valor, não fora param.
Posso recomendar o livro "Framework Design Guidelines" (2ª ed)? As páginas 184-185 abordam as razões para evitar os params. O livro inteiro orientará você na direção certa em todos os tipos de problemas de codificação do .NET.
Aliado ao Framework Design Guidelines é o uso da ferramenta de análise estática, FxCop. Você encontrará isso nos sites da Microsoft como um download gratuito. Execute isso no seu código compilado e veja o que diz. Se reclamar de centenas e centenas de coisas ... não entre em pânico! Olhe com calma e cuidado para o que diz sobre cada caso. Não se apresse para consertar as coisas o mais rápido possível. Aprenda com o que está dizendo. Você será colocado no caminho do domínio.
fonte
Usar a palavra-chave out com um tipo de retorno bool, às vezes pode reduzir o inchaço do código e aumentar a legibilidade. (Principalmente quando as informações extras nos parâmetros de saída são frequentemente ignoradas.) Por exemplo:
vs:
fonte
Não há diferença real. Os parâmetros de saída estão em C # para permitir que o método retorne mais de um valor, só isso.
No entanto, existem algumas pequenas diferenças, mas nenhuma delas é realmente importante:
Usar o parâmetro forçará você a usar duas linhas como:
ao usar o valor de retorno, você poderá fazer isso em uma linha:
Outra diferença (correta apenas para os tipos de valor e apenas se o C # não incorporar a função) é que o uso do valor de retorno fará necessariamente uma cópia do valor quando a função retornar, enquanto o uso do parâmetro OUT não o fará necessariamente.
fonte
out é mais útil quando você está tentando retornar um objeto que você declara no método
Exemplo
fonte
valor de retorno é o valor normal retornado pelo seu método.
Onde como parâmetro out , well out e ref são 2 palavras-chave em C #, eles permitem passar variáveis como referência .
A grande diferença entre ref e out é que ref deve ser inicializado antes e fora , não
fonte
Eu suspeito que não vou dar uma olhada nessa questão, mas sou muito programador experiente e espero que alguns dos leitores mais abertos prestem atenção.
Acredito que ele se adapte melhor às linguagens de programação orientadas a objetos para que seus procedimentos de retorno de valor (VRPs) sejam determinísticos e puros.
'VRP' é o nome acadêmico moderno para uma função que é chamada como parte de uma expressão e tem um valor de retorno que substitui nocionalmente a chamada durante a avaliação da expressão. Por exemplo, em uma declaração como
x = 1 + f(y)
a funçãof
está servindo como um VRP.'Determinístico' significa que o resultado da função depende apenas dos valores de seus parâmetros. Se você chamá-lo novamente com os mesmos valores de parâmetro, certamente obterá o mesmo resultado.
'Puro' significa sem efeitos colaterais: chamar a função não faz nada, exceto calcular o resultado. Isso pode ser interpretado como significando que não é importante efeitos colaterais , na prática; portanto, se o VRP emitir uma mensagem de depuração toda vez que for chamado, por exemplo, isso provavelmente poderá ser ignorado.
Portanto, se, em C #, sua função não é determinística e pura, eu digo que você deve torná-la uma
void
função (em outras palavras, não um VRP), e qualquer valor que ele precise retornar deve ser retornado em umout
ou em umref
parâmetro.Por exemplo, se você tem uma função para excluir algumas linhas de uma tabela de banco de dados e deseja que ela retorne o número de linhas excluídas, deve declarar algo assim:
public void DeleteBasketItems(BasketItemCategory category, out int count);
Se, às vezes, você quiser chamar essa função, mas não obtê-la
count
, sempre poderá declarar uma sobrecarga.Você pode querer saber por que esse estilo combina melhor com a programação orientada a objetos. Em termos gerais, ele se encaixa em um estilo de programação que pode ser (um pouco impreciso) denominado 'programação procedural', e é um estilo de programação procedural que se encaixa melhor na programação orientada a objetos.
Por quê? O modelo clássico de objetos é que eles têm propriedades (também conhecidas como atributos), e você interroga e manipula o objeto (principalmente) lendo e atualizando essas propriedades. Um estilo de programação procedural tende a facilitar isso, porque você pode executar código arbitrário entre operações que obtêm e configuram propriedades.
A desvantagem da programação processual é que, como você pode executar código arbitrário em todo o lugar, pode obter algumas interações muito obtusas e vulneráveis a erros por meio de variáveis globais e efeitos colaterais.
Portanto, de maneira simples, é uma boa prática sinalizar para alguém que está lendo seu código que uma função pode ter efeitos colaterais, tornando-a sem retorno de valor.
fonte
_
símbolo de descarte para ignorar um parâmetro out, por exemplo: DeleteBasketItems (category, out _);