Enums associëren met strings in C#

Ik weet dat het volgende niet mogelijk is omdat het type van de opsomming een int moet zijn

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

Vanuit mijn database krijg ik een veld met onbegrijpelijke codes (de OEMen CMBs). Ik zou van dit veld een enumof iets anders begrijpelijk willen maken. Want als het doel leesbaarheid is, moet de oplossing beknopt zijn.

Welke andere opties heb ik?


Antwoord 1, autoriteit 100%

Ik gebruik graag eigenschappen in een klassein plaats van methoden, omdat ze er meer enum-achtig uitzien.

Hier is een voorbeeld voor een Logger:

public class LogCategory
{
    private LogCategory(string value) { Value = value; }
    public string Value { get; private set; }
    public static LogCategory Trace   { get { return new LogCategory("Trace"); } }
    public static LogCategory Debug   { get { return new LogCategory("Debug"); } }
    public static LogCategory Info    { get { return new LogCategory("Info"); } }
    public static LogCategory Warning { get { return new LogCategory("Warning"); } }
    public static LogCategory Error   { get { return new LogCategory("Error"); } }
}

Geef type-veilige tekenreekswaardendoor als parameter:

public static void Write(string message, LogCategory logCategory)
{
    var log = new LogEntry { Message = message };
    Logger.Write(log, logCategory.Value);
}

Gebruik:

Logger.Write("This is almost like an enum.", LogCategory.Info);

Antwoord 2, autoriteit 43%

U kunt ook het extensiemodel gebruiken:

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

Uw verlengingscursus

public static class MyEnumExtensions
{
    public static string ToDescriptionString(this MyEnum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
           .GetType()
           .GetField(val.ToString())
           .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
} 

gebruik:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());

Antwoord 3, autoriteit 25%

Hoe zit het met het gebruik van een statische klasse met constanten?

static class GroupTypes
{
  public const string TheGroup = "OEM";
  public const string TheOtherGroup = "CMB";
}
void DoSomething(string groupType)
{
  if(groupType == GroupTypes.TheGroup)
  {
    // Be nice
  }  
  else if (groupType == GroupTypes.TheOtherGroup)
  {
    // Continue to be nice
  }
  else
  {
    // unexpected, throw exception?
  }
}

Antwoord 4, autoriteit 7%

Je kunt het eigenlijk heel gemakkelijk doen. Gebruik de volgende code.

enum GroupTypes
{
   OEM,
   CMB
};

Als u vervolgens de tekenreekswaarde van elk enum-element wilt krijgen, gebruikt u gewoon de volgende regel code.

String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);

Ik heb deze methode in het verleden met succes gebruikt en ik heb ook een klasse constanten gebruikt om stringconstanten vast te houden, beide werken redelijk goed, maar ik heb de neiging om hier de voorkeur aan te geven.


Antwoord 5, autoriteit 6%

U kunt attributen toevoegen aan de items in de opsomming en vervolgens reflectie gebruiken om de waarden uit de attributen te halen.

U zou de specificatie “field” moeten gebruiken om de attributen toe te passen, zoals:

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,
    [field:Description("CMB")]
    TheOtherGroup
}

Je zou dan nadenken over de statische velden van het type enum (in dit geval GroupTypes) en de DescriptionAttributevoor de waarde die u zocht met reflectie:

public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
    this T value) where T : struct
{
    // The type of the enum, it will be reused.
    Type type = typeof(T);
    // If T is not an enum, get out.
    if (!type.IsEnum) 
        throw new InvalidOperationException(
            "The type parameter T must be an enum type.");
    // If the value isn't defined throw an exception.
    if (!Enum.IsDefined(type, value))
        throw new InvalidEnumArgumentException(
            "value", Convert.ToInt32(value), type);
    // Get the static field for the value.
    FieldInfo fi = type.GetField(value.ToString(), 
        BindingFlags.Static | BindingFlags.Public);
    // Get the description attribute, if there is one.
    return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
        Cast<DescriptionAttribute>().SingleOrDefault();
}

Ik heb ervoor gekozen om het DescriptionAttributezelf hierboven te retourneren, voor het geval je wilt kunnen bepalen of het attribuut wel of niet is toegepast.


Antwoord 6, autoriteit 6%

Probeer constanten toe te voegen aan een statische klasse. Je krijgt geen Type, maar je hebt leesbare, georganiseerde constanten:

public static class GroupTypes {
    public const string TheGroup = "OEM";
    public const string TheOtherGroup = "CMB";
}

Antwoord 7, autoriteit 4%

Ik heb een structuur gebruikt waarnaar in een eerder antwoord is verwezen, maar heb alle complexiteit weggenomen. Voor mij leek dit het meest op het maken van een opsomming van snaren. Het wordt op dezelfde manier gebruikt als een opsomming.

   struct ViewTypes
    {
        public const string View1 = "Whatever string you like";
        public const string View2 = "another string";
    }

Voorbeeld van gebruik:

  switch( some_string_variable )
   {
      case ViewTypes.View1: /* do something */ break;
      case ViewTypes.View2: /* do something else */ break;
   }

Antwoord 8, autoriteit 3%

Maak een tweede opsomming voor uw DB met het volgende:

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

Nu, u kunt ENUM.PARSE gebruiken om de juiste dbgrouptypes-waarde op te halen van de strings “OEM” en “CMB”. Je kunt degenen omzetten naar INT en de juiste waarden ophalen van de juiste opsomming die u verder wilt gebruiken in uw model.


9, Autoriteit 3%

Gebruik een klasse.

bewerken: beter voorbeeld

class StarshipType
{
    private string _Name;
    private static List<StarshipType> _StarshipTypes = new List<StarshipType>();
    public static readonly StarshipType Ultralight = new StarshipType("Ultralight");
    public static readonly StarshipType Light = new StarshipType("Light");
    public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight");
    public static readonly StarshipType Heavy = new StarshipType("Heavy");
    public static readonly StarshipType Superheavy = new StarshipType("Superheavy");
    public string Name
    {
        get { return _Name; }
        private set { _Name = value; }
    }
    public static IList<StarshipType> StarshipTypes
    {
        get { return _StarshipTypes; }
    }
    private StarshipType(string name, int systemRatio)
    {
        Name = name;
        _StarshipTypes.Add(this);
    }
    public static StarshipType Parse(string toParse)
    {
        foreach (StarshipType s in StarshipTypes)
        {
            if (toParse == s.Name)
                return s;
        }
        throw new FormatException("Could not parse string.");
    }
}

10, Autoriteit 2%

Een andere manier om met het probleem om te gaan, is om een ​​ENUM en een reeks snaren te hebben die de ENUM-waarden in kaart brengen met de lijst met snaren:

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}
string[] GroupTypesStr = {
    "OEM",
    "CMB"
};

U kunt het zoiets gebruiken als dit:

Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);

Het zal CMB

vragen

PROS:

  1. Eenvoudige en reinigingscode.
  2. hoge prestaties (speciaal in vergelijking met die benaderingen
    gebruikt klassen)

Nadelen:

  1. vatbaar om de lijst te verknoeien bij het bewerken ervan, maar het komt goed voor een
    korte lijst.

11, Autoriteit 2%

Hier is de extensie-methode die ik vroeger de ENUM-waarde als string kreeg. Eerst hier is het enum.

public enum DatabaseEnvironment
{
    [Description("AzamSharpBlogDevDatabase")]
    Development = 1, 
    [Description("AzamSharpBlogQADatabase")]
    QualityAssurance = 2, 
    [Description("AzamSharpBlogTestDatabase")] 
    Test = 3
}

Het beschrijving kenmerk kwam uit System.comPonentModel.

en hier is mijn extension-methode:

public static string GetValueAsString(this DatabaseEnvironment environment) 
{
    // get the field 
    var field = environment.GetType().GetField(environment.ToString());
    var customAttributes = field.GetCustomAttributes(typeof (DescriptionAttribute), false);
    if(customAttributes.Length > 0)
    {
        return (customAttributes[0] as DescriptionAttribute).Description;  
    }
    else
    {
        return environment.ToString(); 
    }
}

Nu, u hebt toegang tot de ENUM als tekenreekswaarde met behulp van de volgende code:

[TestFixture]
public class when_getting_value_of_enum
{
    [Test]
    public void should_get_the_value_as_string()
    {
        Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());  
    }
}

12

Hebt u een opzoektabel beschouwd met behulp van een woordenboek?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}
Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

U kunt dan GreenTypePeelookup.tryGetValue () gebruiken om een ​​tekenreeks op te zoeken wanneer u het leest.


13

public class DataType
{
    private readonly string value;
    private static readonly Dictionary<string, DataType> predefinedValues;
    public static readonly DataType Json = new DataType("json");
    public static readonly DataType Xml = new DataType("xml");
    public static readonly DataType Text = new DataType("text");
    public static readonly DataType Html = new DataType("html");
    public static readonly DataType Binary = new DataType("binary");
    static DataType()
    {
        predefinedValues = new Dictionary<string, DataType>();
        predefinedValues.Add(Json.Value, Json);
        predefinedValues.Add(Xml.Value, Xml);
        predefinedValues.Add(Text.Value, Text);
        predefinedValues.Add(Html.Value, Html);
        predefinedValues.Add(Binary.Value, Binary);
    }
    private DataType(string value)
    {
        this.value = value;
    }
    public static DataType Parse(string value)
    {
        var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
        if (string.IsNullOrEmpty(value))
            throw exception;
        string key = value.ToLower();
        if (!predefinedValues.ContainsKey(key))
            throw exception;
        return predefinedValues[key];
    }
    public string Value
    {
        get { return value; }
    }
}

Antwoord 14

Ik zou gewoon een woordenboek maken en de code als sleutel gebruiken.

Bewerken: om de opmerking over het doen van een reverse lookup (het vinden van de sleutel) aan te pakken, zou dit niet erg efficiënt zijn. Als dit nodig is, zou ik een nieuwe klas schrijven om het af te handelen.


Antwoord 15

C# ondersteunt geen opgesomde tekenreeksen, maar voor de meeste situaties kunt u een lijst of woordenboek gebruiken om het gewenste effect te krijgen.

Bijvoorbeeld Om geslaagde/niet geslaagde resultaten af te drukken:

List<string> PassFail = new List<string> { "FAIL", "PASS" };
bool result = true;
Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);

Antwoord 16

Een kleine aanpassing aan de Glennular Extension-methode, zodat je de extensie voor andere dingen dan alleen ENUM’s kunt gebruiken;

using System;
using System.ComponentModel;
namespace Extensions {
    public static class T_Extensions {
        /// <summary>
        /// Gets the Description Attribute Value
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="val">Variable</param>
        /// <returns>The value of the Description Attribute or an Empty String</returns>
        public static string Description<T>(this T t) {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : string.Empty;
        }
    }
}

Of gebruik Linq

using System;
using System.ComponentModel;
using System.Linq;
namespace Extensions {
public static class T_Extensions {
        public static string Description<T>(this T t) =>
            ((DescriptionAttribute[])t
            ?.GetType()
            ?.GetField(t?.ToString())
            ?.GetCustomAttributes(typeof(DescriptionAttribute), false))
            ?.Select(a => a?.Description)
            ?.FirstOrDefault() 
            ?? string.Empty;  
    }
}

Antwoord 17

Waarom niet gewoon dezelfde opsomming gebruiken, maar gewoon .ToString()aanroepen?

using System;
public class EnumSample
{
    enum Holidays
    {
        Christmas = 1,
        Easter = 2
    };
    public static void Main()
    {
        Enum myHolidays = Holidays.Christmas;
        Console.WriteLine("The value of this instance is '{0}'", myHolidays.ToString());
    }
}

Antwoord 18

Ik zou er een klas van maken en een opsomming helemaal vermijden. En dan met het gebruik van een typehandler zou je het object kunnen maken wanneer je het uit de database haalt.

IE:

public class Group
{
    public string Value{ get; set; }
    public Group( string value ){ Value = value; } 
    public static Group TheGroup() { return new Group("OEM"); }
    public static Group OtherGroup() { return new Group("CMB"); }
}

Antwoord 19

Mijn eerste vraag – Heb je toegang tot de database zelf? Dit zou idealiter in de database moeten worden genormaliseerd, anders is elke oplossing vatbaar voor fouten. In mijn ervaring hebben gegevensvelden vol met “OEM” en “CMB” de neiging om in de loop van de tijd dingen als “oem” en andere ‘crap-gegevens’ te vermengen…. Als je het kunt normaliseren, zou je de sleutel kunnen gebruiken in de tabel met de elementen als je Enum, en je bent klaar, met een veel schonere structuur.

Als dat niet beschikbaar is, zou ik je Enum maken en een klasse maken om je string voor je in de Enum te ontleden. Dit zou je op zijn minst enige flexibiliteit geven bij het afhandelen van niet-standaard invoer en veel meer flexibiliteit voor het opvangen of afhandelen van fouten dan het doen van een van de tijdelijke oplossingen met Enum.Parse/Reflection/etc. Een woordenboek zou werken, maar zou kapot kunnen gaan als je ooit problemen hebt met hoofdletters, enz.

Ik raad je aan een les te schrijven zodat je het volgende kunt doen:

// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);

Hierdoor blijft het grootste deel van uw leesbaarheid behouden zonder dat u de DB hoeft te wijzigen.


Antwoord 20

Als ik het goed begrijp, heb je een conversie nodig van string naar enum:

enum GroupTypes {
    Unknown = 0,
    OEM = 1,
    CMB = 2
}
static GroupTypes StrToEnum(string str){
    GroupTypes g = GroupTypes.Unknown;
    try {
        object o = Enum.Parse(typeof(GroupTypes), str, true);
        g = (GroupTypes)(o ?? 0);
    } catch {
    }
    return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");

Je kunt het nog luxer maken met generieke geneesmiddelen voor het type opsomming als je wilt.


Antwoord 21

In VS 2015 kunt u nameof

. gebruiken

public class LogCategory
{
    public static string Trace;
    public static string Debug;
    public static string Info;
    public static string Warning;
    public static string Error;
}

Gebruik:

Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));

Antwoord 22

Ik heb zelfs een paar enums geïmplementeerd, zoals voorgesteld door @Even (via class Xen public static X-leden), om er later achter te komen dat deze dagen, te beginnen met . Net 4.5, er is het rechtToString()methode.

Nu implementeer ik alles weer terug naar opsommingen.


Antwoord 23

Dit is een manier om het als een sterk getypte parameter of als een string te gebruiken:

public class ClassLikeEnum
{
    public string Value
    {
        get;
        private set;
    }
    ClassLikeEnum(string value) 
    {
        Value = value;
    }
    public static implicit operator string(ClassLikeEnum c)
    {
        return c.Value;
    }
    public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomString1");
    public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomString2");
}

Antwoord 24

U kunt twee opsommingen gebruiken. Een voor de database en de andere voor de leesbaarheid.

Je moet er alleen voor zorgen dat ze synchroon blijven, wat een kleine kost lijkt.
U hoeft de waarden niet in te stellen, geef de posities hetzelfde in, maar instellen van de waarden maakt het zeer duidelijk de twee ENUM’s zijn gerelateerd en voorkomt fouten van het herschikken van de ENUM-leden. En een opmerking laat de onderhoudsbemanning weten dat deze gerelateerd zijn en moet synchroon worden gehouden.

// keep in sync with GroupTypes
public enum GroupTypeCodes
{
    OEM,
    CMB
}
// keep in sync with GroupTypesCodes
public enum GroupTypes
{
    TheGroup = GroupTypeCodes.OEM,
    TheOtherGroup = GroupTypeCodes.CMB
}

Om het te gebruiken, converteert u eerst naar de code:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();

Als u vervolgens nog handiger wilt maken, kunt u een verlengingsfunctie toevoegen die alleen voor dit type ENUM werkt:

public static string ToString(this GroupTypes source)
{
    return ((GroupTypeCodes)source).ToString();
}

en u kunt dan gewoon doen:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();

25

Ik ben eigenlijk op zoek naar het reflectie-antwoord door @arthurc

Alleen om zijn antwoord een beetje uit te breiden, kunt u het nog beter maken door een generieke functie te hebben:

   // If you want for a specific Enum
    private static string EnumStringValue(GroupTypes e)
    {
        return EnumStringValue<GroupTypes>(e);
    }
    // Generic
    private static string EnumStringValue<T>(T enumInstance)
    {
        return Enum.GetName(typeof(T), enumInstance);
    } 

Dan kun je alles wat je hebt inpakken

EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part

of

EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic

Antwoord 26

Na het antwoord van @Even Mien heb ik geprobeerd een beetje verder te gaan en het algemeen te maken, ik schijn er bijna te zijn, maar één geval verzet me nog steeds en ik kan mijn code waarschijnlijk een beetje vereenvoudigen.
Ik post het hier als iemand ziet hoe ik het kan verbeteren en vooral laten werken omdat ik het niet kan toewijzen vanuit een string

Tot nu toe heb ik de volgende resultaten:

       Console.WriteLine(TestEnum.Test1);//displays "TEST1"
        bool test = "TEST1" == TestEnum.Test1; //true
        var test2 = TestEnum.Test1; //is TestEnum and has value
        string test3 = TestEnum.Test1; //test3 = "TEST1"
        var test4 = TestEnum.Test1 == TestEnum.Test2; //false
         EnumType<TestEnum> test5 = "TEST1"; //works fine
        //TestEnum test5 = "string"; DOESN'T compile .... :(:(

Waar de magie gebeurt:

public abstract  class EnumType<T>  where T : EnumType<T>   
{
    public  string Value { get; set; }
    protected EnumType(string value)
    {
        Value = value;
    }
    public static implicit operator EnumType<T>(string s)
    {
        if (All.Any(dt => dt.Value == s))
        {
            Type t = typeof(T);
            ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null, new Type[] { typeof(string) }, null);
            return (T)ci.Invoke(new object[] {s});
        }
        else
        {
            return null;
        }
    }
    public static implicit operator string(EnumType<T> dt)
    {
        return dt?.Value;
    }
    public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
    {
        return (string)ct1 == (string)ct2;
    }
    public static bool operator !=(EnumType<T> ct1, EnumType<T> ct2)
    {
        return !(ct1 == ct2);
    }
    public override bool Equals(object obj)
    {
        try
        {
            return (string)obj == Value;
        }
        catch
        {
            return false;
        }
    }
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
    public static IEnumerable<T> All
     => typeof(T).GetProperties()
       .Where(p => p.PropertyType == typeof(T))
       .Select(x => (T)x.GetValue(null, null));
}

Alleen dan hoef ik dit voor mijn opsommingen aan te geven:

public class TestEnum : EnumType<TestEnum> 
{
    private TestEnum(string value) : base(value)
    {}
    public static TestEnum Test1 { get { return new TestEnum("TEST1"); } }
    public static TestEnum Test2 { get { return new TestEnum("TEST2"); } }
}

Antwoord 27

Genomen uit @EvenMien en toegevoegd in enkele opmerkingen. (Ook voor mijn eigen gebruik)

public struct AgentAction
{
    private AgentAction(string value) { Value = value; }
    public string Value { get; private set; }
    public override string ToString()
    {
        return this.Value;
    }
    public static AgentAction Login = new AgentAction("Logout");
    public static AgentAction Logout = new AgentAction("Logout");
    public static implicit operator string(AgentAction action) { return action.ToString(); }
}

Antwoord 28

Deze les toevoegen

public class DatabasePreference {
    public DatabasePreference([CallerMemberName] string preferenceName = "") {
        PreferenceName = preferenceName;
    }
    public string PreferenceName;
}

Dit werk gebruikt CallerMemberNameom de codering te minimaliseren

Gebruik:

//Declare names
public static DatabasePreference ScannerDefaultFlashLight = new DatabasePreference();
public static DatabasePreference ScannerQrCodes = new DatabasePreference();
public static DatabasePreference Scanner1dCodes = new DatabasePreference();

Test het:

Console.WriteLine(ScannerDefaultFlashLight.PreferenceName);
Console.WriteLine(ScannerDefaultFlashLight.Scanner1dCodes);

uitvoer:

ScannerDefaultFlashLight
Scanner1dCodes

Antwoord 29

Op basis van andere meningen kom ik hier op uit. Deze aanpak voorkomt dat u .Value moet typen waar u de constante waarde wilt krijgen.

Ik heb een basisklasse voor alle string-enums zoals deze:

using System;
using Newtonsoft.Json;
[JsonConverter(typeof(ConstantConverter))]
public class StringEnum: IConvertible
{
    public string Value { get; set; }
    protected StringEnum(string value)
    {
        Value = value;
    }
    public static implicit operator string(StringEnum c)
    {
        return c.Value;
    }
    public string ToString(IFormatProvider provider)
    {
        return Value;
    }
    public TypeCode GetTypeCode()
    {
        throw new NotImplementedException();
    }
    public bool ToBoolean(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }
    //The same for all the rest of IConvertible methods
}

De JsonConverter is als volgt:

using System;
using Newtonsoft.Json;
class ConstantConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
        }
        else
        {
            serializer.Serialize(writer, value.ToString());
        }
    }
}

En een echte string-enum ziet er ongeveer zo uit:

public sealed class Colors : StringEnum
{
    public static Colors Red { get { return new Catalog("Red"); } }
    public static Colors Yellow { get { return new Catalog("Yellow"); } }
    public static Colors White { get { return new Catalog("White"); } }
    private Colors(string value) : base(value) { }
}

En hiermee kun je Color.Red gewoon gebruiken om zelfs naar json te serialiseren zonder de eigenschap Value te gebruiken

Other episodes