Retornando mais de um valor em uma função. (C#/.NET)

Retornando mais de um valor em uma função. (C#/.NET)

Overview

Bem-vindo ao universo das tuples em C#! Neste guia prático, vou te mostrar como é possível, e incrivelmente útil, retornar mais de um valor em suas funções em C#, utilizando uma abordagem elegante com tuples. Prepare-se para desvendar os segredos por trás dessa estratégia, compatível com diversas versões do .NET, e veja como pode ser simples manejar dados complexos com uma simplicidade surpreendente. Desde exemplos básicos até estruturas mais elaboradas, estamos prestes a embarcar em uma jornada pelo código que promete refinamento e eficiência nas suas programações. Vamos lá?

Neste post mostro como fazer um função em C# que retorne mais de um valor ao mesmo tempo. Os tipos destes valores não importam para este . Spoiler alert: Vamos utilizar tuples.

Antes de começar com o exemplo, um alerta de compatibilidade: Você só conseguirá utilizar esta abordagem se estiver (pelo menos) em uma destas versões:

FrameworkVersão mínima
.NET Core1.0
.NET Framework4.0
.NET Standard1.0
Xamarin.Android7.1
Xamarin.iOS10.8
Xamarin.Mac3.0

Ok, agora que você já sabe se a versão que está utilizando é compatível ou não, vamos aos exemplos…

A lógica é bem simples: Você vai continuar retornando apenas um valor, mas vai retornar um Tuple que possui os elementos que você precisa.

public Tuple<int, string> ReturnMultiple()
{
     return Tuple.Create(1,"Foo");
}

No exemplo acima, a função está codificada para retornar um Tuple com dois items (ou seja, uma dupla) que contém um integer e uma string.

Para acessar os valores da tuple, utilize as propriedades ItemN, sendo que N vai ser o número da propriedade. (Atenção: É o número da propriedade, ou seja, com base 1.)

> var result = ReturnMultiple();
> result.Item1
1
> result.Item2
"Foo"

No exemplo acima, chamei a função que criei e depois acessei cada uma das propriedades dela.

A tuple é criada através da utilização do méteodo helper chamado Create. Ele permite que você crie desde um singleton (tuple com apenas uma variável) até um óctuplo (oito variáveis em um tuple). De acordo com o site da MSDN, não existem limites para o número de elementos que você pode colocar em um tuple, mas a função (helper) Create permite o máximo de 8 elementos.

Para criar tuples com até oito variáveis, utilize a função Create (como no exemplo acima) e inclua todos os valores separados por virgula.

Se, por alguma razão, você precisar criar um tuple com mais de 8 elementos, precisará utilizar o construtor Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>(T1, T2, T3, T4, T5, T6, T7, TRest) onde, basicamente, você vai concatenando tuples.

Veja o exemplo abaixo (feito no console interativo do C#):

> var bigTuple = new Tuple<int, int, int, int, int, int, int, Tuple<string, string>>(1, 2, 3, 4, 5, 6, 7, Tuple.Create("foo", "bar"));
> bigTuple
[(1, 2, 3, 4, 5, 6, 7, foo, bar)]

No código acima, utilizo o constructor do Tuple, informo os 7 primeiros elementos. No oitavo você cria outro tuple com os valores restantes. Não fica bonito, mas é simples.

Para deixar um exemplo mais completo, veja no exemplo abaixo uma tuple de 20 elementos, que vai ficar assim:

[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, foo, bar)]

Para fazer uma variavel do tipo tuple e com estes elementos, vamos precisar criar 3 tuples…

  1. Vou chamar de innerTuple a que vai conter os 6 ultimos elementos;
  2. A midTuple que vai conter 8 elementos, sendo que o oitavo é a innerTuple;
  3. e a superTuple, que também vai conter 8 elementos, sendo que o último é a midTuple.

Achei bem confusa a abordagem e não consegui ver nenhuma aplicação prática para uma tuple deste tamanho, mas resolvi insistir na criação de um exemplo dela.

Vamos começar:

var innerTuple = Tuple.Create(15, 16, 17, 18, "foo", "bar");
var midTuple = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int, int,string, string>>(8, 9, 10, 11, 12, 13, 14, innerTuple);

Para criar esta tuple, temos que começar de dentro para fora. Então comecei criando a innerTuple e depois a midTuple (que contem a innerTuple).

Note que, para declarar a midTuple eu precisei incluir a estrutura da innerTuple. A mesma lógica se aplica a superTuple.

var superTuple = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int, int, int, int, int, Tuple<int, int, int, int, string, string>>>(1, 2, 3, 4, 5, 6, 7, midTuple);

No constructor da superTuple precisei incluir toda a estrutura das outras duas tuples. Ficou meio que um inception de tuples.

Essa superTuple é bem complexa, mas a utilização de uma tuple com poucos elementos me parece bem útil.

Referências:

  1. MSDN: Tuple.Create
  2. MSDN: Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>(T1, T2, T3, T4, T5, T6, T7, TRest)