Pergunta

Se queremos obter um valor de um método, podemos usar qualquer valor de retorno, como esta:

public int GetValue(); 

ou

public void GetValue(out int x);

Eu realmente não entendo as diferenças entre eles, e por isso, não sei o que é melhor. Você pode me explicar isso?

Obrigado.

Foi útil?

Solução

Os valores de retorno são quase sempre a escolha certa quando o método não tem mais nada para retorno. (Na verdade, eu não consigo pensar em quaisquer casos onde eu nunca quer um método vazio com um parâmetro out, se eu tivesse a escolha. C # 7 de métodos Deconstruct para desconstrução apoiada em língua atua como muito, muito rara exceção a esta regra.)

Além de qualquer outra coisa, ele pára o chamador de ter que declarar a variável separadamente:

int foo;
GetValue(out foo);

vs

int foo = GetValue();

Os valores Out também evitar método de encadeamento como esta:

Console.WriteLine(GetValue().ToString("g"));

(Na verdade, esse é um dos problemas com setters de propriedade, bem como, e é por isso que as padrão Builder usa métodos que retornam o construtor, por exemplo myStringBuilder.Append(xxx).Append(yyy).)

Além disso, os parâmetros são um pouco mais difícil de usar com reflexão e, geralmente, fazer o teste mais difícil também. (Mais esforço é normalmente colocado em tornando mais fácil para valores de retorno de simulação do que os parâmetros). Basicamente não há nada que eu posso pensar que eles fazem mais fácil ...

Valores de retorno FTW.

EDIT: Em termos do que está acontecendo ...

Basicamente, quando você passar um argumento para um "fora" parâmetro, Have para passar em uma variável. (Elementos de matriz são classificadas como variáveis ??também.) O método que você chamar não tem um "novo" variável 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:

using System;

class Test
{
    static int value;

    static void ShowValue(string description)
    {
        Console.WriteLine(description + value);
    }

    static void Main()
    {
        Console.WriteLine("Return value test...");
        value = 5;
        value = ReturnValue();
        ShowValue("Value after ReturnValue(): ");

        value = 5;
        Console.WriteLine("Out parameter test...");
        OutParameter(out value);
        ShowValue("Value after OutParameter(): ");
    }

    static int ReturnValue()
    {
        ShowValue("ReturnValue (pre): ");
        int tmp = 10;
        ShowValue("ReturnValue (post): ");
        return tmp;
    }

    static void OutParameter(out int tmp)
    {
        ShowValue("OutParameter (pre): ");
        tmp = 10;
        ShowValue("OutParameter (post): ");
    }
}

Resultado:

Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10

A diferença está no "post" passo - ou seja, após a variável local ou parâmetro foi alterado. No teste ReturnValue, isso não faz diferença para a variável value estática. No teste OutParameter, a variável value é alterado pelo tmp = 10; linha

Outras dicas

O que é melhor, depende de sua situação particular. Um de existe a razões out é facilitar retorno de vários valores de uma chamada de método:

public int ReturnMultiple(int input, out int output1, out int output2)
{
    output1 = input + 1;
    output2 = input + 2;

    return input;
}

Portanto, não é, por definição melhor do que o outro. Mas normalmente você iria querer usar um simples retorno, a menos que você tem a situação acima, por exemplo.

EDIT: Este é um exemplo que demonstra uma das razões que existe a palavra-chave. A descrição acima é de modo algum ser considerada uma prática recomendada.

Você deve geralmente preferem um valor de retorno ao longo de um out param. Fora params são um mal neccissary se você se encontrar escrevendo código que precisa fazer 2 coisas. Um bom exemplo disso é o padrão Try (como Int32.TryParse).

Vamos considerar o que o interlocutor de seus dois métodos teria que fazer. Para o primeiro exemplo que eu posso escrever isso ...

int foo = GetValue();

Observe que eu posso declarar uma variável e atribuir-lhe pelo seu método em uma linha. Para o segundo exemplo é parecido com este ...

int foo;
GetValue(out foo);

Agora estou forçado a declarar minha variável na frente e escrever meu código em duas linhas.

update

Um bom lugar para olhar ao pedir esses tipos de pergunta é as Diretrizes de Design do .NET Framework. Se você tiver a versão do livro, em seguida, você pode ver as anotações por Anders Hejlsberg e outros sobre este assunto (página 184-185), mas a versão online está aqui ...

http://msdn.microsoft.com/en -us / library / ms182131 (VS.80) .aspx

Se você achar que precisa para retornar duas coisas a partir de uma API, em seguida, envolvê-los em uma struct / classe seria melhor do que um fora param.

Há uma razão para usar um param out que já não tenha sido 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, tornando-se uma das forças out o chamador especificamente aceito-o:

 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore

Claro que o chamador ainda pode ignorar o valor em uma param out, mas você chamou sua atenção a ele.

Esta é uma necessidade rara; mais frequentemente, você deve usar uma exceção para um problema genuíno ou retornar um objeto com informações de estado para um "FYI", mas poderia haver circunstâncias em que isso é importante.

É de preferência principalmente

Eu prefiro retornos e se você tiver vários retornos você pode envolvê-los em um resultado DTO

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}

Você deve quase sempre utilizar um valor de retorno. parâmetros 'out' criar um pouco de atrito para um monte de APIs, composicionalidade, etc.

A exceção mais notável que vem à mente é quando você quiser retornar vários valores (.Net Framework não tem tuplas até 4,0), como com o padrão TryParse.

Você só pode ter um valor de retorno ao passo que você pode ter vários parâmetros de saída.

Você só precisa considerar os parâmetros nesses casos.

No entanto, se você precisa de retornar mais de um parâmetro do seu método, você provavelmente vai querer olhar para o que você está voltando de uma abordagem OO e considerar se você é melhor fora de retornar um objeto ou uma estrutura com estes parâmetros . Portanto, você está de volta para um valor de retorno novamente.

Eu preferiria o seguinte em vez de um desses neste exemplo simples.

public int Value
{
    get;
    private set;
}

Mas, eles são todos muito parecidos. Normalmente, só usaria 'out' se eles precisam para passar vários valores de volta a partir do método. Se você quiser enviar um valor dentro e fora do método, pode-se escolher 'ref'. Meu método é melhor, se você está apenas retornando um valor, mas se você quiser passar um parâmetro e obter um valor de volta seria provavelmente escolher a sua primeira escolha.

Ambos têm um propósito diferente e não são tratados da mesma pelo compilador. Se o seu método precisa retornar um valor, então você deve usar retorno. Fora é usado onde seus método precisa retornar vários valores.

Se você usar o retorno, em seguida, os dados são primeiro escrito para os métodos de empilhar e depois na chamada do método. Enquanto no caso de fora, está escrito diretamente para a pilha de métodos de chamada. Não tenho certeza se existem mais diferenças.

Não há nenhuma diferença real, os parâmetros estão em C # para permitir método de retorno de mais de um valor, isso é tudo.

No entanto, existem algumas pequenas diferenças, mas não deles são realmente importante:

Usando o parâmetro irá impor-lhe utilizar duas linhas como:

int n;
GetValue(n);

enquanto estiver usando valor de retorno vai deixar você fazer isso em uma linha:

int n = GetValue();

Outra diferença (correto somente para tipos de valor e somente se C # não em linha da função) é que o uso de valor de retorno irá necessariamente fazer uma cópia do valor quando o retorno de função, enquanto usando o parâmetro OUT não necessariamente fazê-lo.

Como já foi dito:. Valor de retorno, não out param

Maio eu recomendo a você o livro "Framework Design Guidelines" (2ª ed)? Páginas 184-185 cobrir as razões para evitar a params. Todo o livro vai orientar você na direção certa em todos os tipos de .NET codificação questões.

Allied com as Diretrizes de Design do Framework é o uso da ferramenta de análise estática, FxCop. Você encontrará este em sites da Microsoft como um download gratuito. Executar este em seu código compilado e ver o que ele diz. Se ele se queixa de centenas e centenas de coisas ... não entre em pânico! Olhar com calma e cuidado com o que ele diz sobre cada caso. Não se apresse para consertar as coisas o mais rápido possível. Aprender com o que ele está dizendo a você. Você será colocado no caminho para a mestria.

Eu acho que um dos poucos cenários onde seria útil seria quando se trabalha com memória não gerenciada, e você quer torná-lo óbvio que o valor "retornou" devem ser eliminados manualmente, em vez de esperar que ele seja descartado por conta própria.

Além disso, valores de retorno são compatíveis com paradigmas de projeto assíncronas.

Você não pode designar uma "assíncrono" função se ele usa ref ou out parâmetros.

Em resumo, Valores de retorno permitir método de encadeamento, sintaxe mais limpa (eliminando a necessidade para o chamador para declarar variáveis ??adicionais), e permitir projetos assíncronos sem a necessidade de alterações substanciais no futuro.

Usando a palavra-chave com um tipo de retorno de bool, às vezes pode reduzir o inchaço de código e aumentar a legibilidade. (Principalmente quando a informação extra na out param é frequentemente ignorado.) Por exemplo:

var result = DoThing();
if (result.Success)
{
    result = DoOtherThing()
    if (result.Success)
    {
        result = DoFinalThing()
        if (result.Success)
        {
            success = true;
        }
    }
}

vs:

var result;
if (DoThing(out result))
{
    if (DoOtherThing(out result))
    {
        if (DoFinalThing(out result))
        {
            success = true;
        }
    }
}

out é mais útil quando você está tentando retornar um objeto que você declarar no método.

Exemplo

public BookList Find(string key)
{
   BookList book; //BookList is a model class
   _books.TryGetValue(key, out book) //_books is a concurrent dictionary
                                     //TryGetValue gets an item with matching key and returns it into book.
   return book;
}

valor de retorno é o valor normal que é devolvida pelo seu método.

Onde como a parâmetro, bem fora e ref são 2 palavras-chave do C # que permitem passar variáveis ??como referência .

A grande diferença entre ref e a é, ref deve ser inicializado antes e a não

Eu suspeito que eu não vou dar uma olhada-in sobre esta questão, mas eu sou um muito programador experiente, e espero que alguns dos leitores de mente mais aberta vai prestar atenção.

Eu acredito que ele se adapte às linguagens de programação orientada a objeto melhor para os seus procedimentos de retorno de valor (VRPs) para ser determinista e puro.

'VRP' é o nome acadêmica moderna para uma função que é chamado como parte de uma expressão, e tem um valor de retorno que teoricamente substitui a chamada durante a avaliação da expressão. Por exemplo. em uma declaração como x = 1 + f(y) a função f está servindo como um VRP.

meios 'determinísticos' que o resultado da função depende somente dos valores de seus parâmetros. Se você chamá-lo novamente com os mesmos valores de parâmetro, você está certo de obter o mesmo resultado.

'Pure' significa sem efeitos colaterais: chamar a função não faz nada , exceto computar o resultado. Isso pode ser interpretado como significando nenhum importante efeitos colaterais, na prática, por isso, se o VRP gera uma mensagem de depuração de cada vez que é chamado, por exemplo, que provavelmente pode ser ignorado.

Assim, se, em C #, a sua função não é determinista e puro, eu digo que você deve torná-lo uma função void (em outras palavras, não um VRP), e qualquer valor que necessita para retorno deve ser devolvido em qualquer um out ou um parâmetro ref.

Por exemplo, se você tem uma função para apagar algumas linhas de uma tabela de banco de dados, e você quer que ele retorne o número de linhas que excluídos, você deve declará-la algo como isto:

public void DeleteBasketItems(BasketItemCategory category, out int count);

Se você às vezes quero chamar essa função, mas não obter o count, você sempre pode declarar uma sobrecarga.

Você pode querer saber por este ternos de estilo de Programação Orientada a Objetos melhor. Em termos gerais, ele se encaixa em um estilo de programação que poderia ser (um pouco imprecisamente) denominado 'programação processual', e é um estilo de programação processual que se encaixa objeto programação orientada melhor.

Por quê? O modelo clássico de objetos é que eles têm propriedades (aka atributos), e você interrogar e manipular o objeto (principalmente) através da leitura e atualizar essas propriedades. Um estilo de programação processual tende a torná-lo mais fácil de fazer isso, porque você pode executar código arbitrário no entre as operações que começam e definir propriedades.

A desvantagem de programação procedural é que, porque você pode executar código arbitrário em todo o lugar, você pode obter algumas interações muito obtusos e bugs vulnerável através de variáveis ??globais e efeitos colaterais.

Assim, muito simplesmente, é uma boa prática para sinal para alguém ler o seu código que a função poderia ter efeitos colaterais, tornando-o não-valor de retorno.

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