Considere uma função que retorna dois valores. Nós 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 melhor prática e por quê?
struct
conformeEric
mencionado.Respostas:
Cada um deles tem seus prós e contras.
Os parâmetros de saída são rápidos e baratos, mas exigem que você passe uma variável e dependa da mutação. É quase impossível usar corretamente um parâmetro out com LINQ.
Tuplas pressionam a coleta de lixo e não são autodocumentadas. "Item1" não é muito descritivo.
Estruturas personalizadas podem ser lentas para copiar se forem grandes, mas são autodocumentáveis e eficientes se forem pequenas. No entanto, também é uma dor 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 no 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.
fonte
Somando-se às respostas anteriores, C # 7 traz tuplas de tipo de valor, ao contrário de
System.Tuple
ser um tipo de referência e também oferece semântica aprimorada.Você ainda pode deixá-los sem nome e usar a
.Item*
sintaxe:(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()
fonte
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
TryParse
métodos usam umout
parâmetro para aceitar o valor analisado e retornam abool
para indicar se a análise foi bem-sucedida ou não. Os dois valores não pertencem realmente um ao outro, portanto, semanticamente, faz mais sentido, e a intenção do código é mais fácil de ler, usar oout
parâmetro.Se, no entanto, sua função retornar as coordenadas X / Y de algum objeto na tela, então os dois valores semanticamente pertencem um ao outro e seria melhor usar a
struct
.Eu pessoalmente evito usar um
tuple
para qualquer coisa que seja visível para o código externo por causa da sintaxe estranha para recuperar os membros.fonte
out
parâmetronull
. Existem alguns tipos imutáveis anuláveis por aí.try
padrão que funciona com interfaces covariantes éT TryGetValue(whatever, out bool success)
; essa abordagem teria permitido interfacesIReadableMap<in TKey, out TValue> : IReadableMap<out TValue>
e permitir que o código que deseja mapear instâncias deAnimal
para instâncias deCar
aceitar umDictionary<Cat, ToyotaCar>
[usandoTryGetValue<TKey>(TKey key, out bool success)
. Essa variação não é possível seTValue
for usado como umref
parâmetro.Eu irei 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 de fato não pode ser feito retornando apenas um parâmetro de saída), irei para a segunda abordagem.
fonte
out
. Além disso, há umaparams
palavra - chave que não mencionei para esclarecer a questão.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 os tipos de referência funcionam.
https://msdn.microsoft.com/en-us/library/ms182131.aspx
Tuple é bom para uso interno, mas o uso é estranho em API pública. Então, meu voto é entre struct e classe para API pública.
fonte
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.
fonte