Partilhar via


Como usar a geração de fontes em System.Text.Json

A geração de código-fonte está System.Text.Json disponível no .NET 6 e versões posteriores. Quando usado em um aplicativo, a versão de idioma do aplicativo deve ser C# 9.0 ou posterior. Este artigo mostra como usar a serialização com suporte de geração de origem em seus aplicativos.

Para obter informações sobre os diferentes modos de geração de origem, consulte Modos de geração de origem.

Usar padrões de geração de origem

Para usar a geração de origem com todos os padrões (ambos os modos, opções padrão):

  1. Crie uma classe parcial que deriva de JsonSerializerContext.

  2. Especifique o tipo a ser serializado ou desserializado aplicando JsonSerializableAttribute à classe de contexto.

  3. Chame um JsonSerializer método que:

Por padrão, ambos os modos de geração de origem são usados se você não especificar um. Para obter informações sobre como especificar o modo a ser usado, consulte Especificar modo de geração de origem mais adiante neste artigo.

Aqui está o tipo usado nos seguintes exemplos:

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

Aqui está a classe de contexto configurada para fazer a geração de origem para a classe anterior WeatherForecast :

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}

Os tipos de WeatherForecast membros não precisam ser explicitamente especificados com [JsonSerializable] atributos. Os membros declarados como object exceções a esta regra. O tipo de tempo de execução para um membro declarado como object precisa ser especificado. Por exemplo, suponha que você tenha a seguinte classe:

public class WeatherForecast
{
    public object? Data { get; set; }
    public List<object>? DataList { get; set; }
}

E você sabe que em tempo de execução ele pode ter boolean e int objetos:

WeatherForecast wf = new() { Data = true, DataList = new List<object> { true, 1 } };

Em seguida, boolean e int tem de ser declarado como [JsonSerializable]:

[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(int))]
public partial class WeatherForecastContext : JsonSerializerContext
{
}

Para especificar a geração de origem para uma coleção, use [JsonSerializable] com o tipo de coleção. Por exemplo: [JsonSerializable(typeof(List<WeatherForecast>))].

JsonSerializer Métodos que usam a geração de origem

Nos exemplos a seguir, a propriedade static Default do tipo de contexto fornece uma instância do tipo de contexto com opções padrão. A instância de contexto fornece uma WeatherForecast propriedade que retorna uma JsonTypeInfo<WeatherForecast> instância. Você pode especificar um nome diferente para essa propriedade usando a TypeInfoPropertyName [JsonSerializable] propriedade do atributo.

Exemplos de serialização

Utilização de JsonTypeInfo<T>:

jsonString = JsonSerializer.Serialize(
    weatherForecast!, SourceGenerationContext.Default.WeatherForecast);

Utilização de JsonSerializerContext:

jsonString = JsonSerializer.Serialize(
    weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);

Utilização de JsonSerializerOptions:

sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default
};

jsonString = JsonSerializer.Serialize(
    weatherForecast, typeof(WeatherForecast), sourceGenOptions);

Exemplos de desserialização

Utilização de JsonTypeInfo<T>:

weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
    jsonString, SourceGenerationContext.Default.WeatherForecast);

Utilização de JsonSerializerContext:

weatherForecast = JsonSerializer.Deserialize(
    jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
    as WeatherForecast;

Utilização de JsonSerializerOptions:

var sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default
};
weatherForecast = JsonSerializer.Deserialize(
    jsonString, typeof(WeatherForecast), sourceGenOptions)
    as WeatherForecast;

Exemplo de programa completo

Aqui estão os exemplos anteriores em um programa completo:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace BothModesNoOptions
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSourceGenerationOptions(WriteIndented = true)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SourceGenerationContext : JsonSerializerContext
    {
    }

    public class Program
    {
        public static void Main()
        {
            string jsonString = """
                {
                    "Date": "2019-08-01T00:00:00",
                    "TemperatureCelsius": 25,
                    "Summary": "Hot"
                }
                """;
            WeatherForecast? weatherForecast;

            weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                jsonString, SourceGenerationContext.Default.WeatherForecast);
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            weatherForecast = JsonSerializer.Deserialize(
                jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
                as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            var sourceGenOptions = new JsonSerializerOptions
            {
                TypeInfoResolver = SourceGenerationContext.Default
            };
            weatherForecast = JsonSerializer.Deserialize(
                jsonString, typeof(WeatherForecast), sourceGenOptions)
                as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            jsonString = JsonSerializer.Serialize(
                weatherForecast!, SourceGenerationContext.Default.WeatherForecast);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}

            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}

            sourceGenOptions = new JsonSerializerOptions
            {
                TypeInfoResolver = SourceGenerationContext.Default
            };

            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), sourceGenOptions);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
        }
    }
}

Especificar o modo de geração de origem

Você pode especificar o modo baseado em metadados ou o modo de otimização de serialização para um contexto inteiro, que pode incluir vários tipos. Ou você pode especificar o modo para um tipo individual. Se você fizer as duas coisas, a especificação de modo para um tipo vence.

Exemplo do modo de otimização de serialização (caminho rápido)

  • Para todo um contexto:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializeOnlyContext : JsonSerializerContext
    {
    }
    
  • Para um tipo individual:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
    internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
  • Exemplo de programa completo

    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace SerializeOnlyNoOptions
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
            public int TemperatureCelsius { get; set; }
            public string? Summary { get; set; }
        }
    
        [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
        [JsonSerializable(typeof(WeatherForecast))]
        internal partial class SerializeOnlyContext : JsonSerializerContext
        {
        }
        
        [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
        internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
        {
        }
    
         public class Program
        {
            public static void Main()
            {
                string jsonString;
                WeatherForecast weatherForecast = new()
                    { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" };
    
                // Use context that selects Serialization mode only for WeatherForecast.
                jsonString = JsonSerializer.Serialize(weatherForecast,
                    SerializeOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
    
                // Use a context that selects Serialization mode.
                jsonString = JsonSerializer.Serialize(weatherForecast,
                    SerializeOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
            }
        }
    }
    

Exemplo de modo baseado em metadados

  • Para todo um contexto:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class MetadataOnlyContext : JsonSerializerContext
    {
    }
    
    jsonString = JsonSerializer.Serialize(
        weatherForecast!, MetadataOnlyContext.Default.WeatherForecast);
    
    weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
        jsonString, MetadataOnlyContext.Default.WeatherForecast);
    
  • Para um tipo individual:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Metadata)]
    internal partial class MetadataOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
    jsonString = JsonSerializer.Serialize(
        weatherForecast!,
        MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
    
    weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
        jsonString, MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
    
  • Exemplo de programa completo

    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace MetadataOnlyNoOptions
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
            public int TemperatureCelsius { get; set; }
            public string? Summary { get; set; }
        }
    
        [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Metadata)]
        internal partial class MetadataOnlyWeatherForecastOnlyContext : JsonSerializerContext
        {
        }
    
        [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
        [JsonSerializable(typeof(WeatherForecast))]
        internal partial class MetadataOnlyContext : JsonSerializerContext
        {
        }
    
        public class Program
        {
            public static void Main()
            {
                string jsonString = """
                    {
                      "Date": "2019-08-01T00:00:00",
                      "TemperatureCelsius": 25,
                      "Summary": "Hot"
                    }
                    """;
                WeatherForecast? weatherForecast;
    
                // Deserialize with context that selects metadata mode only for WeatherForecast only.
                weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                    jsonString, MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine($"Date={weatherForecast?.Date}");
                // output:
                //Date=8/1/2019 12:00:00 AM
    
                // Serialize with context that selects metadata mode only for WeatherForecast only.
                jsonString = JsonSerializer.Serialize(
                    weatherForecast!,
                    MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
    
                // Deserialize with context that selects metadata mode only.
                weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                    jsonString, MetadataOnlyContext.Default.WeatherForecast);
                Console.WriteLine($"Date={weatherForecast?.Date}");
                // output:
                //Date=8/1/2019 12:00:00 AM
    
                // Serialize with context that selects metadata mode only.
                jsonString = JsonSerializer.Serialize(
                    weatherForecast!, MetadataOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
            }
        }
    }
    

Suporte à geração de origem no ASP.NET Core

Em aplicativos Blazor, use sobrecargas e HttpClientJsonExtensions.PostAsJsonAsync métodos de extensão que tomam um contexto de geração de HttpClientJsonExtensions.GetFromJsonAsync origem ou TypeInfo<TValue>.

A partir do .NET 8, você também pode usar sobrecargas de métodos de extensão que aceitam um contexto de geração de HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable origem ou TypeInfo<TValue>.

Em aplicativos Razor Pages, MVC, SignalR e API Web, use a JsonSerializerOptions.TypeInfoResolver propriedade para especificar o contexto.

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions.TypeInfoResolverChain.Add(MyJsonContext.Default));

Nota

JsonSourceGenerationMode.Serializationou serialização de caminho rápido, não é suportada para serialização assíncrona.

No .NET 7 e versões anteriores, essa limitação também se aplica a sobrecargas síncronas que JsonSerializer.Serialize aceitam um Streamarquivo . A partir do .NET 8, embora a serialização de streaming exija modelos baseados em metadados, ela voltará ao caminho rápido se as cargas úteis forem conhecidas por serem pequenas o suficiente para caber no tamanho predeterminado do buffer. Para obter mais informações, veja https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.

Desativar padrões de reflexão

Como System.Text.Json usa reflexão por padrão, chamar um método de serialização básico pode quebrar aplicativos AOT nativos, que não suportam todas as APIs de reflexão necessárias. Essas quebras podem ser difíceis de diagnosticar, uma vez que podem ser imprevisíveis, e os aplicativos geralmente são depurados usando o tempo de execução CoreCLR, onde a reflexão funciona. Em vez disso, se você desabilitar explicitamente a serialização baseada em reflexão, as quebras serão mais fáceis de diagnosticar. O código que usa a serialização baseada em reflexão fará com que uma InvalidOperationException mensagem com uma descritiva seja lançada em tempo de execução.

Para desabilitar o reflexo padrão em seu aplicativo, defina a JsonSerializerIsReflectionEnabledByDefault propriedade MSBuild como false em seu arquivo de projeto:

<PropertyGroup>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
  • O comportamento dessa propriedade é consistente independentemente do tempo de execução, CoreCLR ou Native AOT.
  • Se você não especificar essa propriedade e PublishTrimmed estiver habilitado, a serialização baseada em reflexão será automaticamente desabilitada.

Você pode verificar programaticamente se a reflexão está desabilitada usando a JsonSerializer.IsReflectionEnabledByDefault propriedade. O trecho de código a seguir mostra como você pode configurar seu serializador dependendo se a reflexão está habilitada:

static JsonSerializerOptions CreateDefaultOptions()
{
    return new()
    {
        TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
            ? new DefaultJsonTypeInfoResolver()
            : MyContext.Default
    };
}

Como a propriedade é tratada como uma constante de tempo de link, o método anterior não enraíza o resolvedor baseado em reflexão em aplicativos executados na AOT nativa.

Especificar opções

No .NET 8 e versões posteriores, a maioria das opções que você pode definir usando JsonSerializerOptions também pode ser definida usando o JsonSourceGenerationOptionsAttribute atributo. A vantagem de definir opções através do atributo é que a configuração é especificada em tempo de compilação, o que garante que a propriedade gerada MyContext.Default seja pré-configurada com todas as opções relevantes definidas.

O código a seguir mostra como definir opções usando o JsonSourceGenerationOptionsAttribute atributo.

[JsonSourceGenerationOptions(
    WriteIndented = true,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SerializationModeOptionsContext : JsonSerializerContext
{
}

Ao usar JsonSourceGenerationOptionsAttribute para especificar opções de serialização, chame um dos seguintes métodos de serialização:

  • Um JsonSerializer.Serialize método que usa um TypeInfo<TValue>arquivo . Passe-lhe a Default.<TypeName> propriedade da sua classe de contexto:

    jsonString = JsonSerializer.Serialize(
        weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
    
  • Um JsonSerializer.Serialize método que toma um contexto. Passe-lhe a Default propriedade estática da sua classe de contexto.

    jsonString = JsonSerializer.Serialize(
        weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
    

Se você chamar um método que permite que você passe em sua própria instância de , a configuração do Utf8JsonWriterIndented escritor será honrada em vez da JsonSourceGenerationOptionsAttribute.WriteIndented opção.

Se você criar e usar uma instância de contexto chamando o construtor que usa uma JsonSerializerOptions instância, a instância fornecida será usada em vez das opções especificadas por JsonSourceGenerationOptionsAttribute.

Aqui estão os exemplos anteriores em um programa completo:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SerializeOnlyWithOptions
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSourceGenerationOptions(
        WriteIndented = true,
        PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
        GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializationModeOptionsContext : JsonSerializerContext
    {
    }
    public class Program
    {
        public static void Main()
        {
            string jsonString;
            WeatherForecast weatherForecast = new()
                { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" };

            // Serialize using TypeInfo<TValue> provided by the context
            // and options specified by [JsonSourceGenerationOptions].
            jsonString = JsonSerializer.Serialize(
                weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
            Console.WriteLine(jsonString);
            // output:
            //{
            //  "date": "2019-08-01T00:00:00",
            //  "temperatureCelsius": 0,
            //  "summary": "Hot"
            //}

            // Serialize using Default context
            // and options specified by [JsonSourceGenerationOptions].
            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
            Console.WriteLine(jsonString);
            // output:
            //{
            //  "date": "2019-08-01T00:00:00",
            //  "temperatureCelsius": 0,
            //  "summary": "Hot"
            //}
        }
    }
}

Combine geradores de origem

Você pode combinar contratos de vários contextos gerados pela fonte dentro de uma única JsonSerializerOptions instância. Use a JsonSerializerOptions.TypeInfoResolver propriedade para encadear vários contextos que foram combinados usando o JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]) método.

var options = new JsonSerializerOptions
{
    TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default);
};

A partir do .NET 8, se você quiser anexar ou anexar outro contexto, poderá fazê-lo usando a JsonSerializerOptions.TypeInfoResolverChain propriedade. A ordenação da cadeia é significativa: JsonSerializerOptions consulta cada um dos resolvedores em sua ordem especificada e retorna o primeiro resultado que não é nulo.

options.TypeInfoResolverChain.Add(ContextD.Default); // Append to the end of the list.
options.TypeInfoResolverChain.Insert(0, ContextE.Default); // Insert at the beginning of the list.

Qualquer alteração feita na propriedade é refletida TypeInfoResolverChain por TypeInfoResolver e vice-versa.

Serializar campos enum como cadeias de caracteres

Por padrão, enums são serializados como números. Para serializar os campos de um enum específico como strings ao usar a geração de código-fonte, anote-o com o JsonStringEnumConverter<TEnum> conversor. Ou para definir uma política geral para todas as enumerações, use o JsonSourceGenerationOptionsAttribute atributo.

JsonStringEnumConverter<T> conversor

Para serializar nomes de enum como cadeias de caracteres usando a geração de código-fonte, use o JsonStringEnumConverter<TEnum> conversor. (O tipo não genérico JsonStringEnumConverter não é suportado pelo tempo de execução nativo do AOT.)

Anote o tipo de enumeração com o JsonStringEnumConverter<TEnum> conversor usando o JsonConverterAttribute atributo:

public class WeatherForecastWithPrecipEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Precipitation? Precipitation { get; set; }
}

[JsonConverter(typeof(JsonStringEnumConverter<Precipitation>))]
public enum Precipitation
{
    Drizzle, Rain, Sleet, Hail, Snow
}

Crie uma JsonSerializerContext classe e anote-a com o JsonSerializableAttribute atributo:

[JsonSerializable(typeof(WeatherForecastWithPrecipEnum))]
public partial class Context1 : JsonSerializerContext { }

O código a seguir serializa os nomes de enum em vez dos valores numéricos:

var weatherForecast = new WeatherForecastWithPrecipEnum
{
    Date = DateTime.Parse("2019-08-01"),
    TemperatureCelsius = 25,
    Precipitation = Precipitation.Sleet
};

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    TypeInfoResolver = Context1.Default,
};
string? jsonString = JsonSerializer.Serialize(weatherForecast, options);

O JSON resultante se parece com o exemplo a seguir:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Precipitation": "Sleet"
}

Política geral

Em vez de usar o JsonStringEnumConverter<TEnum> tipo, você pode aplicar uma política de cobertor para serializar enums como cadeias de caracteres usando o JsonSourceGenerationOptionsAttribute. Crie uma JsonSerializerContext classe e anote-a com os JsonSerializableAttribute atributos e JsonSourceGenerationOptionsAttribute :

[JsonSourceGenerationOptions(UseStringEnumConverter = true)]
[JsonSerializable(typeof(WeatherForecast2WithPrecipEnum))]
public partial class Context2 : JsonSerializerContext { }

Observe que o enum não tem o JsonConverterAttribute:

public class WeatherForecast2WithPrecipEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Precipitation2? Precipitation { get; set; }
}

public enum Precipitation2
{
    Drizzle, Rain, Sleet, Hail, Snow
}

Nomes de membros enum personalizados

A partir do .NET 9, você pode personalizar nomes de membros enum usando o atributo JsonStringEnumMemberName. Para obter mais informações, consulte Nomes de membros enum personalizados.

Consulte também