- .NET 8.0, 9.0, 10.0
- Newtonsoft.Json 13.0.4+
- System.Text.Json 8.0.5+
Define your StringEnum clean and simple:
public class MyPet : StringEnum<MyPet>
{
public static MyPet Monkey = New(); // = "Monkey"
public static MyPet Cat = New();
public static MyPet Rabbit = New();
}More initialization options:
public class MyPet : StringEnum<MyPet>
{
public static MyPet Rabbit = New("Rabbits");
public static MyPet Dog = New(EnumCase.Upper, "Dog"); // MyPet.Dog.ToString() -> "DOG"
public static MyPet Ghost = New(null); // handy when values in dataobject may have null values
public static MyPet Empty = New(string.Empty);
}Add additional properties for your StringEnum:
public class MyFlower : StringEnum<MyFlower>
{
public static MyFlower Rose = New().HasPropertyValue(x => x.AdditionalInfo, "Big");
public static MyFlower Camomile = New()
.HasPropertyValue(x => x.AdditionalInfo, "Small")
.HasPropertyValue(x => x.DefaultQuantity, 15);
// your custom properties here:
public string AdditionalInfo { get; protected set; }
public int? DefaultQuantity { get; protected set; }
}var mouse = MyPet.Mouse;
if (mouse == "Mouse") // compare with string without .ToString()
{
return true;
}
if (mouse == MyPet.Parse("mouse")) // parsing is case insensitive
{
return true;
}
// implicit conversions example
string cat = MyPet.Cat;
Assert.IsTrue(cat == "Cat");
string dog = (MyPet)"Dog";
Assert.IsTrue(dog == "Dog");// Returns true if parsing succeeds, false otherwise
if (MyPet.TryParse("Cat", out var pet))
{
Console.WriteLine($"Parsed: {pet}");
}
// Handle null values
if (MyPet.TryParse(null, out var ghostPet))
{
// ghostPet will be the null-valued enum member if one exists
}// StringEnum supports comparison operators
if (MyPet.Cat < MyPet.Dog)
{
Console.WriteLine("Cat comes before Dog alphabetically");
}
// CompareTo method
int result = MyPet.Cat.CompareTo(MyPet.Dog); // negative value
result = MyPet.Cat.CompareTo(MyPet.Cat); // 0
result = MyPet.Dog.CompareTo(MyPet.Cat); // positive value// AsList() and Parse() use internal caching for performance
var allPets = MyPet.AsList(); // cached after first call
// Multiple Parse calls use cache
var cat1 = MyPet.Parse("Cat"); // first call initializes cache
var cat2 = MyPet.Parse("Cat"); // retrieved from cache[JsonConverter(typeof(JsonStringEnumConverter<MyFlower>))]
public class MyFlower : StringEnum<MyFlower>
{
public static MyFlower Rose = New();
public static MyFlower Hibiscus = New();
}
public class GardenFlower
{
public MyFlower FlowerType { get; set; }
public int Quantity { get; set; }
}
string jsonData = "{'FlowerType' : 'Rose', 'Quantity' : 2 }";
var obj = JsonConvert.DeserializeObject<GardenFlower>(jsonData);
Assert.IsTrue(obj.FlowerType == "Rose");
Assert.IsTrue(obj.FlowerType == MyFlower.Rose);using System.Text.Json.Serialization;
[JsonConverter(typeof(SystemTextJsonStringEnumConverter<MyFlower>))]
public class MyFlower : StringEnum<MyFlower>
{
public static MyFlower Rose = New();
public static MyFlower Hibiscus = New();
}
public class GardenFlower
{
public MyFlower FlowerType { get; set; }
public int Quantity { get; set; }
}
string jsonData = """{"FlowerType" : "Rose", "Quantity" : 2 }""";
var obj = JsonSerializer.Deserialize<GardenFlower>(jsonData);
Assert.IsTrue(obj.FlowerType == "Rose");
Assert.IsTrue(obj.FlowerType == MyFlower.Rose);[TypeConverter(typeof(StringEnumConverter<MyFlower>))] // default type converter
public class MyFlower : StringEnum<MyFlower>
{
public static MyFlower Rose = New();
public static MyFlower Hibiscus = New();
}
// TypeConverter usage
TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(MyFlower));
var rose = (MyFlower)typeConverter.ConvertFrom(null, Thread.CurrentThread.CurrentCulture, "Rose");
// IConvertible usage
var fl = MyFlower.Hibiscus;
var res = Convert.ChangeType(fl, typeof(string));
Assert.IsTrue((string)res == "Hibiscus");
// GetTypeCode returns TypeCode.String
Assert.AreEqual(TypeCode.String, fl.GetTypeCode());- Define your model:
public class PersonType : StringEnum<PersonType>
{
public static PersonType EM = New();
public static PersonType SP = New();
public static PersonType SC = New();
public static PersonType VC = New();
public static PersonType IN = New();
public static PersonType GC = New();
}
[Table(Name = "[Person].[Person]")]
public class Person
{
[PrimaryKey, Identity]
public int BusinessEntityID { get; set; }
[Column]
public PersonType PersonType { get; set; } // string values "EM", "SP", "SC" ... etc.
}- Setup type conversion via
MappingSchema:
using LinqToDB;
using LinqToDB.Mapping;
// Create mapping schema with converters
var ms = new MappingSchema();
// Register converters for PersonType
ms.SetConverter<PersonType, string>(v => v.Value);
ms.SetConverter<string, PersonType>(s => s == null ? null : PersonType.Parse(s));
// Apply to your data connection
var options = new DataOptions()
.UseSqlServer(connectionString)
.UseMappingSchema(ms);
using var db = new DataConnection(options);Or using FluentMappingBuilder:
var ms = new MappingSchema();
var builder = new FluentMappingBuilder(ms);
builder.Entity<Person>()
.Property(e => e.PersonType)
.HasConversion(
v => v.Value,
s => s == null ? null : PersonType.Parse(s));
var options = new DataOptions()
.UseSqlServer(connectionString)
.UseMappingSchema(ms);- Usage:
// select records
var persons = await db.GetTable<Person>().ToListAsync();
// update record (use .Value for parameters)
var pers = new Person() { PersonType = PersonType.VC, BusinessEntityID = 1675 };
await db.GetTable<Person>()
.Where(x => x.BusinessEntityID == pers.BusinessEntityID)
.Set(x => x.PersonType, pers.PersonType.Value)
.UpdateAsync();[Keyless]
public class PersonTitle : StringEnum<PersonTitle>
{
public static PersonTitle Mr = New("Mr.");
public static PersonTitle Ms = New("Ms.");
public static PersonTitle Mss = New("Ms");
public static PersonTitle Mrs = New("Mrs.");
public static PersonTitle Sr = New("Sr.");
public static PersonTitle Sra = New("Sra.");
public static PersonTitle Undefined = New(null);
}
// setup converter in OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Person>()
.Property(e => e.Title)
.HasConversion(
v => v.Value,
v => v == null ? null : PersonTitle.Parse(v));
base.OnModelCreating(modelBuilder);
}| Feature | Description |
|---|---|
| Strong typing | Type-safe string enums with compile-time checking |
| Case-insensitive parsing | Parse() and TryParse() ignore case |
| Null support | New(null) creates null-valued members |
| Custom properties | HasPropertyValue() for additional data |
| JSON serialization | Newtonsoft.Json and System.Text.Json support |
| IComparable | Comparison operators and CompareTo() |
| IConvertible | Convert to/from other types |
| TypeConverter | Design-time and runtime conversion |
| Caching | AsList() and Parse() use internal caching |
| ORM integration | Linq2DB and EF Core support |
dotnet add package StringEnum.NetMIT License - see LICENSE.md for details