Generalizando tipos de retornos assíncronos no C# 7.0 \| TreinaWeb               Promoção no ar   Matricule-se agora e garanta **54% de desconto**  

  Termina em   Tempo restante da oferta: 02 Horas 

 42 Min 

 43 Seg 

   Tempo restante da oferta: 02 42 43 

  [Assinar →](https://www.treinaweb.com.br/checkout/pagamento/plano/anual?cupom=TW-SCLIENTE26) 

   [                ](https://www.treinaweb.com.br)  Explorar  

 [ Quanto custa? ](#assinatura) [ FAQ ](https://www.treinaweb.com.br#faq) [Matricule-se](#assinatura) [ Entrar ](https://www.treinaweb.com.br/login) 

     [ Início ](https://www.treinaweb.com.br) [ Artigos ](https://www.treinaweb.com.br/blog) Generalizando tipos de retornos assíncronos no C# 7.0  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

# Generalizando tipos de retornos assíncronos no C# 7.0

 Aprenda a criar um tipo que pode ser retornado pelos métodos assíncronos do C#.

 [ Wladimilson M. Nascimento ](https://www.treinaweb.com.br/blog/autor/wladimilson-m-nascimento) 9 anos atrás

  ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2018/01/19114832/C-SHARP-7.png)  

Até a versão 6.0 do C#, os métodos assíncronos poderiam retornar os tipos **Task**, **Task** e **void**.

Por se tratar de um objeto, em algumas situações os retornos de **Task**, podem apresentar problemas de performance. Alocado na memória `heap` e coletado pelo garbage coletor, ao fazer uso intenso de métodos assíncronos, a performance de uma aplicação pode ser impactada pela volumosa alocação dos objetos **Task**.

Para resolver este problema, na versão 7.0 do C#, foi adicionado o recurso que permite criar tipos de retorno para os métodos assíncronos.

[  ![C# (C Sharp) Básico](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/csharp.svg)   Curso C# (C Sharp) Básico Conhecer o curso ](https://www.treinaweb.com.br/curso/csharp-basico)

## Regras para a criação de um tipo **Task**

Ao ler a [documentação](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/async-return-types) sobre os tipos de retorno assíncrono, é dito que qualquer tipo que contenha um método `GetAwaiter` público, que retorne um objeto que implemente a interface [`System.Runtime.CompilerServices.ICriticalNotifyCompletion`](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.icriticalnotifycompletion), pode ser utilizado. Mas não é apenas isso.

Além deste detalhe, os tipos retornados por um método assíncrono, devem seguir um padrão “task type”. Pode ser uma classe ou estrutura, mas precisam estar associados a um *builder type*, identificado com o atributo `System.Runtime.CompilerServices.AsyncMethodBuilderAttribute`. Caso retornem valores, deve ser definido como um tipo genérico.

O “tipo task” em si, só necessita implementar o método `GetAwaiter` público, mas o objeto retornado por este método, deve implementar a interface `ICriticalNotifyCompletion`, o método ` GetResult` e possuir uma propriedade pública chamada ` IsCompleted`.

Já o *builder type* a ser criado, deve corresponder a classe ou estrutura definida. Não se pode utilizar um existente e deve possuir a estrutura abaixo:

```csharp
class MyTaskMethodBuilder
{
    public static MyTaskMethodBuilder Create();

    public void Start(ref TStateMachine stateMachine)
        where TStateMachine : IAsyncStateMachine;

    public void SetStateMachine(IAsyncStateMachine stateMachine);
    public void SetException(Exception exception);
    public void SetResult(T result);

    public void AwaitOnCompleted(
        ref TAwaiter awaiter, ref TStateMachine stateMachine)
        where TAwaiter : INotifyCompletion
        where TStateMachine : IAsyncStateMachine;
    public void AwaitUnsafeOnCompleted(
        ref TAwaiter awaiter, ref TStateMachine stateMachine)
        where TAwaiter : ICriticalNotifyCompletion
        where TStateMachine : IAsyncStateMachine;

    public MyTask Task { get; }
}

```

Para tipos não genéricos, o método `SetResult` não possui parâmetro.

A classe acima será utilizada pelo compilador para transformar tipo assíncrono como um método assíncrono na compilação para o MSIL.

Você pode ver mais detalhes do funcionamento desta classe, [aqui](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md#execution).

Parece complicado? Vamos a um exemplo para entender estes pontos.

## Criando um tipo assíncrono/Task

Inicialmente criarei uma classe que implementará a interface `ICriticalNotifyCompletion`, que chamarei de `MyTaskAwaiter`:

```csharp
public class MyTaskAwaiter : ICriticalNotifyCompletion
{
    //Retorna se a operação foi concluída
    public bool IsCompleted => _value.IsCompleted;
    private readonly MyTask _value;

    //Inicializa a classe com a classe Task criada
    public MyTaskAwaiter(MyTask value)
    {
        this._value = value;
    }

    //Retorna o resultado
    public TResult GetResult() => _value.GetResult();

    //Define uma continuação.
    public void OnCompleted(Action continuation)
    {
        _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation);
    }

    //Define uma continuação.
    public void UnsafeOnCompleted(Action continuation)
    {
        _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation);
    }
}

```

Os métodos mais importantes desta classe são, o `GetResult` e o `OnCompleted`, que, respectivamente, retorna o resultado da “Task”, e informa quando ela foi concluída.

Note que a “Task” é uma classe customizada, que será definida com o seguinte código:

```csharp
[AsyncMethodBuilder(typeof(MyTaskBuilder))]
public class MyTask
{
    //Define uma propriedade Task para indicar quando uma operação assincrona foi finalizada
    private Task _task;

    //O resultado retornado pela classe
    private TResult _result;

    //Indica que a operação foi finalizada ou não
    public bool IsCompleted => _task == null || _task.IsCompleted;

    //Inicializando a classe com o resultado da operação bem sucedida
    public MyTask(TResult result){
        this._task = null;
        this._result = result;
    }

    //Obtém o "Awaiter" da classe
    public MyTaskAwaiter GetAwaiter() => new MyTaskAwaiter(this);

    //Retorna uma task, ou cria uma para o resultado
    public Task AsTask() => _task ?? Task.FromResult(_result);

    //Retorna o resultado
    public TResult GetResult() =>
        _task == null ? 
            _result : 
            _task.GetAwaiter().GetResult();
}

```

Mesmo necessitando apenas de um método `GetAwaiter`, note que a classe definiu outros métodos e propriedades para facilitar o seu uso.

Por fim, é necessário definir o *builder type* para a classe acima, que deve ter o código abaixo:

```csharp
public class MyTaskBuilder
{
    private AsyncTaskMethodBuilder _methodBuilder;
    private TResult _result;
    private bool _haveResult;
    private bool _useBuilder;

    //Cria o Buider Type
    public static MyTaskBuilder Create() => new MyTaskBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };

    //Inicia o Buider Type
    public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { _methodBuilder.Start(ref stateMachine); }

    //Define o State Machine para o Buider Type
    public void SetStateMachine(IAsyncStateMachine stateMachine) { _methodBuilder.SetStateMachine(stateMachine); }

    //Define o resultado
    public void SetResult(TResult result)
    {
        if (_useBuilder)
        {
            _methodBuilder.SetResult(result);
        }
        else
        {
            _result = result;
            _haveResult = true;
        }
    }

    //Gera uma exceção
    public void SetException(Exception exception) => _methodBuilder.SetException(exception);

    //Retorna a task vinculado ao builder type
    public MyTask Task {
        get {
            if (_haveResult)
            {
                return new MyTask(_result);
            }
            else
            {
                _useBuilder = true;
                return new MyTask(_methodBuilder.Task.Result);
            }
        }
    }

    //Define o comportamento quando for necessário aguardar a conclusão da operação assincronona
    public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine 
    {
        _useBuilder = true;
        _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
    }

    //Define o comportamento quando for necessário aguardar a conclusão da operação assincronona
    public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { 
        _useBuilder = true;
        _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
    }
}

```

Com a definição dessas três classes, podemos retornar o tipo ` MyTask` em métodos assíncronos.

## Utilizando o tipo assíncrono

O uso desta classe não difere do uso das classes `Task` ou `Task` em um método assíncrono:

```csharp
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Retorno: " + MyMethod().GetResult());
    }

    public static async MyTask MyMethod(){
        var result = await MyMethodAsync();

        return result;
    }

    public static MyTask MyMethodAsync()
    {
        return new MyTask(5);
    }
}

```

Mesmo permitindo a criação de tipos assíncronos, criar um não é algo recomendado. Tudo que vimos acima só deve ser utilizado em casos específicos. Se o objetivo for apenas melhorar a performance da aplicação, basta substituir o tipo **Task**, pelo **ValueTask**.

## ValueTask

O tipo **System.Threading.Tasks.ValueTask** foi adicionado na versão 7.0 do C#, como uma forma de superar os gargalos da classe **Task**. Definido como uma estrutura, os objetos de **ValueTask** não são salvos na memória `heap`, o que já contorna o problema com alocação de memória da classe **Task**.

O seu uso é bem simples:

```csharp
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Retorno: " + MyMethod().Result);
    }

    public static async ValueTask MyMethod(){
        var result = await MyMethodAsync();

        return result;
    }

    public static ValueTask MyMethodAsync()
    {
        return new ValueTask(5);
    }
}

```

E por não ser removida da memória pelo garbage collector, ela permite até a criação de “cache”:

```csharp
class Program
{
    static void Main(string[] args)
    {
var task1 = CachedMethod();
        Console.WriteLine("Retorno da primeira chamada: " + task1.Result);

        var task2 = CachedMethod();
        Console.WriteLine("Retorno da segunda chamada: " + task2.Result);

        var task3 = CachedMethod();
        Console.WriteLine("Retorno da segunda chamada: " + task3.Result);
    }

    public static ValueTask CachedMethod()
    {
        return (cache) ? new ValueTask(cacheResult) : new ValueTask(LoadCache());
    }
    private static bool cache = false;
    private static int cacheResult;
    private static async Task LoadCache()
    {
        // simulando um processamento assincrono:
        await Task.Delay(100);
        cacheResult = new Random().Next(5000, 10000);
        cache = true;
        return cacheResult;
    }
}

```

A execução do código acima será:

![Resultado da execução do código](https://dkrn4sk0rn31v.cloudfront.net/2018/01/17173055/Resultado-execucao.png)

## Conclusão

Como recomendado na documentação, no C# 7.0, procure sempre utilizar a classe **ValueTask**, pois o seu uso já se provou ser mais performático que a classe **Task**.

[  ![C# (C Sharp) Básico](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/csharp.svg)   Curso C# (C Sharp) Básico Conhecer o curso ](https://www.treinaweb.com.br/curso/csharp-basico)

[  ![C# (C Sharp) Intermediário](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/csharp.svg)   Curso C# (C Sharp) Intermediário Conhecer o curso ](https://www.treinaweb.com.br/curso/csharp-intermediario)

[  ![C# (C Sharp) Avançado](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/csharp.svg)   Curso C# (C Sharp) Avançado Conhecer o curso ](https://www.treinaweb.com.br/curso/csharp-avancado)

- [ #C ](https://www.treinaweb.com.br/blog/tag/c)
- [ #C# 7.0 ](https://www.treinaweb.com.br/blog/tag/c-7-0)
- [ #ValueTask ](https://www.treinaweb.com.br/blog/tag/valuetask)

Autor

 ![Wladimilson M. Nascimento](//secure.gravatar.com/avatar/f0dd442f156a3eacd2880e9cd0eafbd1?d=mm)

## Wladimilson M. Nascimento

 Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo. 

 [Todos os artigos](https://www.treinaweb.com.br/blog/autor/wladimilson-m-nascimento)  

## Continue estudando

 Transforme leitura em prática com os cursos e formações da TreinaWeb.

 [Ver cursos](https://www.treinaweb.com.br/cursos)   

  Continue lendo

## Artigos relacionados

- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2019/08/24120107/streams-400x280.jpg)  [ PHP ](https://www.treinaweb.com.br/blog/categoria/php) 

     7 anos atrás

    ##  [ Streams no PHP ](https://www.treinaweb.com.br/blog/streams-no-php) 

     Você, desenvolvedor PHP, já teve a oportunidade de trabalhar mais intimamente com Streams? Se você já teve ou não, esse artigo é pra você! Uma introdução ao essencial sobre o assunto.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2019/10/20234042/capa-dart-400x280.png)  [ Dart ](https://www.treinaweb.com.br/blog/categoria/dart) 

     5 anos atrás

    ##  [ Como utilizar generics no Dart ](https://www.treinaweb.com.br/blog/como-utilizar-generics-no-dart) 

     Neste artigo vamos aprender sobre os Generics na linguagem Dart e como eles podem nos auxiliar em garantir que os tipos dos objetos sejam o que esperamos que eles sejam.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2020/08/conheca-o-padrao-arquitetural-porto-para-aplicacoes-back-end-400x280.png)  [ Desenvolvimento Back-end ](https://www.treinaweb.com.br/blog/categoria/desenvolvimento-back-end) 

     6 anos atrás

    ##  [ Conheça o padrão arquitetural Porto para aplicações back-end ](https://www.treinaweb.com.br/blog/conheca-o-padrao-arquitetural-porto-para-aplicacoes-back-end) 

     Conheça o padrão arquitetural Porto! Voltado para aplicações back-end, ele permite escrever monolitos que podem ser facilmente migrados para micro serviços.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2021/01/conhecendo-variaveis-e-constantes-no-python-400x280.png)  [ Python ](https://www.treinaweb.com.br/blog/categoria/python) 

     6 anos atrás

    ##  [ Conhecendo variáveis e constantes no Python ](https://www.treinaweb.com.br/blog/conhecendo-variaveis-e-constantes-no-python) 

     Conheça neste artigo as variáveis e constantes no Python.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2019/06/11140050/sockets-redes-tcp-udp-400x280.png)  [ Rede de computadores ](https://www.treinaweb.com.br/blog/categoria/rede-de-computadores) 

     8 anos atrás

    ##  [ Uma introdução a TCP, UDP e Sockets ](https://www.treinaweb.com.br/blog/uma-introducao-a-tcp-udp-e-sockets) 

     Uma introdução (base teórica) para TCP, UDP e Sockets, principalmente para desenvolvedores que desejam programar com Sockets.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2017/07/checklist-de-seguranca-para-autenticacao-400x280.png)  [ Segurança da Informação ](https://www.treinaweb.com.br/blog/categoria/seguranca-da-informacao) 

     10 anos atrás

    ##  [ Checklist de segurança para autenticação ](https://www.treinaweb.com.br/blog/checklist-de-seguranca-para-autenticacao) 

     Cuidar da segurança é um dos pilares para a sustentação de qualquer aplicação na web. Sem o mínimo não é possível nem mesmo garantir uma razoável disponibilidade.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2021/05/87asgh12-400x280.png)  [ Orientação a Objetos ](https://www.treinaweb.com.br/blog/categoria/orientacao-a-objetos) 

     10 anos atrás

    ##  [ Devo usar herança ou composição? ](https://www.treinaweb.com.br/blog/devo-usar-heranca-ou-composicao) 

     A composição permite um reuso e extensão de código mais flexível que a herança clássica. Mas isso é motivo para sempre a escolhermos em detrimento à herança clássica?

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2024/05/generalista-ou-especialista-400x280.png)  [ Carreira ](https://www.treinaweb.com.br/blog/categoria/carreira) 

     2 anos atrás

    ##  [ Prós e contras entre Especialização e Generalização em TI ](https://www.treinaweb.com.br/blog/pros-e-contras-entre-especializacao-e-generalizacao-em-ti) 

     Está em dúvida se segue o caminho de especialização ou generalização em sua carreira de TI? Confira os pontos levantados nesse artigo.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2021/02/c-sharp-consumindo-apis-com-flurl-400x280.png)  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

     6 anos atrás

    ##  [ C# - Testando requisições com Flurl ](https://www.treinaweb.com.br/blog/c-testando-requisicoes-com-flurl) 

     Implemente testes unitários em requisições HTTP com o auxílio de Flurl.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2021/02/c-sharp-consumindo-apis-com-flurl-400x280.png)  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

     6 anos atrás

    ##  [ C# - Consumindo APIs com Flurl ](https://www.treinaweb.com.br/blog/c-consumindo-apis-com-flurl) 

     Veja como consumir dados de uma API no C#, utilizando a biblioteca Flurl.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2020/11/C-SHARP-PROPRIEDADES-INIT-RECORD-400x280.png)  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

     6 anos atrás

    ##  [ C# 9.0 - Inteiros nativos e inferência de tipos ](https://www.treinaweb.com.br/blog/c-9-0-inteiros-nativos-e-inferencia-de-tipos) 

     Conheça os novos tipos de dados introduzidos no C# 9.0, os inteiros nativos e os novos recursos da inferência de tipos.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2020/11/C-SHARP-PROPRIEDADES-INIT-RECORD-400x280.png)  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

     6 anos atrás

    ##  [ C# 9.0 - Programas top-level e Pattern Matching ](https://www.treinaweb.com.br/blog/c-9-0-programas-top-level-e-pattern-matching) 

     Dando continuidade ao nosso estudo do C# 9.0, neste artigo veremos dois novos recursos dele: Programas top-leve e Pattern Matching.

     Ler artigo

## Um ano de acesso total para você viver de programação.

 Todos os cursos e formações da TreinaWeb numa única assinatura, com professores que atuam no mercado, suporte direto e certificados. Do primeiro `console.log` ao mercado de trabalho.

- **1 ano** de acesso a **todos os cursos**
- Cursos novos **toda semana**
- Suporte **direto com professores**
- Plano de carreira **personalizado**
- **Certificados digitais** inclusos
- **Aplicativos** para Android e iOS, com **acesso offline**

    **Garantia incondicional de satisfação** 

 Teste por 7 dias e, se não fizer sentido para você, devolvemos seu dinheiro.

### Acesso completo a todos os cursos e dezenas de Formações.

 12 meses 

  Economize R$ 840,00  54% OFF 

 de 12x R$ 129,00 por apenas

 12x  R$ 59,00

 sem juros no cartão de crédito ou R$ 599,00 à vista

  Oferta termina em  **02h 42min 43s**

- Acesso imediato e ilimitado durante 1 ano.
- Plano de carreira personalizado.
- Suporte direto com professores.
- E muito mais!

 [Matricule-se agora](https://www.treinaweb.com.br/checkout/pagamento/plano/anual?cupom=TW-SCLIENTE26)

     [                ](https://www.treinaweb.com.br)

 Escola online de programação, tecnologia e IA.

- [  ](https://www.facebook.com/TreinaWeb/)
- [  ](https://www.instagram.com/treinaweb/)
- [  ](https://www.youtube.com/user/TreinaWeb)
- [  ](https://twitter.com/treinaweb)
- [  ](https://www.linkedin.com/company/treinaweb)
- [  ](https://github.com/treinaweb)

## Inscreva-se em nossa newsletter

Receba lançamentos, promoções e novidades.

   Seu nome     Seu WhatsApp     Seu melhor e-mail   Inscrever-se 

## Cursos

- [ Base para Devs ](https://www.treinaweb.com.br/categoria/base-para-devs)
- [ Front-end ](https://www.treinaweb.com.br/categoria/desenvolvimento-front-end)
- [ Back-end ](https://www.treinaweb.com.br/categoria/desenvolvimento-back-end)
- [ Mobile ](https://www.treinaweb.com.br/categoria/desenvolvimento-mobile)
- [ Bancos de Dados ](https://www.treinaweb.com.br/categoria/bancos-de-dados)
- [ Cloud ](https://www.treinaweb.com.br/categoria/cloud-computing)
- [ IA ](https://www.treinaweb.com.br/categoria/ia)
- [ E mais ](https://www.treinaweb.com.br/categoria/e-mais)
- [ Ver todos os cursos ](https://www.treinaweb.com.br/cursos)

## Conteúdo

- [ Formações ](https://www.treinaweb.com.br/formacoes)
- [ Projetos práticos ](https://www.treinaweb.com.br/projetos-praticos)
- [ Direto ao ponto ](https://www.treinaweb.com.br/direto-ao-ponto)
- [ Planos ](https://www.treinaweb.com.br#assinatura)
- [ Depoimentos ](https://www.treinaweb.com.br#depoimentos)
- [ Comunidade ](https://www.treinaweb.com.br#comunidade)
- [ Corpo docente ](https://www.treinaweb.com.br#docente)

## A empresa

- [ Sobre a TreinaWeb ](https://www.treinaweb.com.br#sobre)
- [ Perguntas frequentes ](https://www.treinaweb.com.br#faq)
- [ Vantagens de estudar na TreinaWeb ](https://www.treinaweb.com.br/vantagens-de-estudar-na-treinaweb)
- [ Cursos para empresas ](https://www.treinaweb.com.br/empresas)
- [ Sugira um novo curso ](https://www.treinaweb.com.br/sugerir-curso)
- [ Trabalhe conosco ](https://www.treinaweb.com.br/trabalhe-conosco)
- [ Artigos ](https://www.treinaweb.com.br/blog)
- [ Desenvolvedores e agentes ](https://www.treinaweb.com.br/developers)
- [ Contato ](https://www.treinaweb.com.br/contato)
- [ Política de privacidade ](https://www.treinaweb.com.br/politica-de-privacidade)
- [ Termos de uso ](https://www.treinaweb.com.br/termos-de-uso)

## Baixe nosso aplicativo

 [   Disponível na **App Store**  ](https://apps.apple.com/us/app/treinaweb/id1322729447) [   Disponível no **Google Play**  ](https://play.google.com/store/apps/details?id=br.com.treinaweb.mobile) 

  Av. Paulista, 1765, Conj 71 e 72 · Bela Vista · São Paulo · SP · 01311-200   © 2004 – 2026 TreinaWeb Tecnologia LTDA · CNPJ 06.156.637/0001-58
