Pergunta

Considere uma função que retorna dois valores.Podemos escrever:

// Using out:
string MyFunction(string input, out int count)

// Using Tuple class:
Tuple<string, int> MyFunction(string input)

// Using struct:
MyStruct MyFunction(string input)

Qual é a prática recomendada e por quê?

Foi útil?

Solução

Cada um deles tem seus prós e contras.

Os parâmetros de saída são rápidos e baratos, mas requerem que você passe uma variável e dependa da mutação.É quase impossível usar corretamente um parâmetro out com LINQ.

As tuplas exercem pressão sobre a coleção e não são autodocumentadas."Item1" não é muito descritivo.

Estruturas personalizadas podem demorar para copiar se forem grandes, mas são autodocumentáveis e eficientes se forem pequenas.No entanto, também é difícil definir um monte de estruturas personalizadas para usos triviais.

Eu estaria inclinado para a solução de estrutura personalizada, todas as outras coisas sendo iguais.Ainda melhor, porém, é fazer uma função que retorne apenas um valor .Por que você está retornando dois valores em primeiro lugar?

ATUALIZAÇÃO: observe que as tuplas em C # 7, enviadas seis anos após a redação deste artigo, são tipos de valor e, portanto, menos propensos a criar pressão de coleção.

Outras dicas

Acho que a resposta depende da semântica do que a função está fazendo e da relação entre os dois valores.

Por exemplo, os métodos TryParse usam um parâmetro out para aceitar o valor analisado e retornam um bool para indicar se a análise foi bem-sucedida ou não.Os dois valores realmente não pertencem um ao outro, portanto, semanticamente, faz mais sentido, e a intenção do código é mais fácil de ler, usar o parâmetro out.

Se, no entanto, sua função retornar coordenadas X / Y de algum objeto na tela, os dois valores semanticamente pertencem um ao outro e seria melhor usar um struct.

Eu pessoalmente evitaria usar um tuple para qualquer coisa que fosse visível para o código externo devido à sintaxe estranha para recuperar os membros.

Somando-se às respostas anteriores, C # 7 traz tuplas de tipo de valor, ao contrário do System.Tuple que é um tipo de referência e também oferece semântica aprimorada.

Você ainda pode deixá-los sem nome e usar a sintaxe .Item*:

(string, string, int) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.Item1; //John
person.Item2; //Doe
person.Item3;   //42

Mas o que é realmente poderoso sobre esse novo recurso é a capacidade de ter tuplas nomeadas.Portanto, poderíamos reescrever o acima assim:

(string FirstName, string LastName, int Age) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.FirstName; //John
person.LastName; //Doe
person.Age;   //42

A desestruturação também é suportada:

(string firstName, string lastName, int age) = getPerson()

Vou seguir com a abordagem de usar o parâmetro Out porque na segunda abordagem você exigiria criar um objeto da classe Tuple e então agregar valor a ele, o que eu acho uma operação cara em comparação com retornar o valor do parâmetro out.No entanto, se você quiser retornar vários valores na classe Tupla (o que não pode ser conseguido apenas retornando um parâmetro de saída), irei para a segunda abordagem.

Você não mencionou mais uma opção, que é ter uma classe personalizada em vez de struct.Se os dados têm semântica associada a eles que pode ser operada por funções, ou o tamanho da instância é grande o suficiente (> 16 bytes como regra prática), uma classe personalizada pode ser preferida. O uso de "out" não é recomendado na API pública por causa de sua associação a ponteiros e requer compreensão de como funcionam os tipos de referência.

https://msdn.microsoft.com/en-us/library/ms182131.aspx

Tuple é bom para uso interno, mas o uso é estranho na API pública. Então, meu voto é entre struct e classe para API pública.

Não existe uma "prática recomendada".É com o que você se sente confortável e o que funciona melhor em sua situação.Contanto que você seja consistente com isso, não há problema com nenhuma das soluções que você postou.

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