C
C#2mo ago
Indeed

String enums - current consensus

Hi! What is the current consensus on string enum Any special library, Some abstract class that defines helper methods with attributes etc. Example usage:
public enum AuthTokenStatus {
ACTIVE = 'Y',
INACTIVE = 'N'
}
public enum AuthTokenStatus {
ACTIVE = 'Y',
INACTIVE = 'N'
}
13 Replies
Somgör from Human Resources
afaik enums are numbers
Indeed
Indeed2mo ago
I understand that My point is how does one go about implementing custom string enums in c# What is the currently agreed upon standard
Somgör from Human Resources
technically you could do
public enum AuthTokenStatus {
ACTIVE = 1,
INACTIVE = 0
}
public enum AuthTokenStatus {
ACTIVE = 1,
INACTIVE = 0
}
Indeed
Indeed2mo ago
some Enumeration abstract class like so
public abstract class Enumeration : IComparable
{
public string Name { get; private set; }

public int Id { get; private set; }

protected Enumeration(int id, string name) => (Id, Name) = (id, name);

public override string ToString() => Name;

public static IEnumerable<T> GetAll<T>() where T : Enumeration =>
typeof(T).GetFields(BindingFlags.Public |
BindingFlags.Static |
BindingFlags.DeclaredOnly)
.Select(f => f.GetValue(null))
.Cast<T>();

public override bool Equals(object obj)
{
if (obj is not Enumeration otherValue)
{
return false;
}

var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = Id.Equals(otherValue.Id);

return typeMatches && valueMatches;
}

public int CompareTo(object other) => Id.CompareTo(((Enumeration)other).Id);

// Other utility methods ...
}
public abstract class Enumeration : IComparable
{
public string Name { get; private set; }

public int Id { get; private set; }

protected Enumeration(int id, string name) => (Id, Name) = (id, name);

public override string ToString() => Name;

public static IEnumerable<T> GetAll<T>() where T : Enumeration =>
typeof(T).GetFields(BindingFlags.Public |
BindingFlags.Static |
BindingFlags.DeclaredOnly)
.Select(f => f.GetValue(null))
.Cast<T>();

public override bool Equals(object obj)
{
if (obj is not Enumeration otherValue)
{
return false;
}

var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = Id.Equals(otherValue.Id);

return typeMatches && valueMatches;
}

public int CompareTo(object other) => Id.CompareTo(((Enumeration)other).Id);

// Other utility methods ...
}
public class CardType
: Enumeration
{
public static CardType Amex = new(1, nameof(Amex));
public static CardType Visa = new(2, nameof(Visa));
public static CardType MasterCard = new(3, nameof(MasterCard));

public CardType(int id, string name)
: base(id, name)
{
}
}
public class CardType
: Enumeration
{
public static CardType Amex = new(1, nameof(Amex));
public static CardType Visa = new(2, nameof(Visa));
public static CardType MasterCard = new(3, nameof(MasterCard));

public CardType(int id, string name)
: base(id, name)
{
}
}
some library handling it in compiletime etc. there are many ways to go on about it, which is currently proposed to be the best one
Somgör from Human Resources
Arent Enumerations things you loop over?
Indeed
Indeed2mo ago
you're talking about Enumerables most go for static readonly strings the point is I later deserialize them in dapper into values to use in queries
public async Task<Result<IEnumerable<AuthTokenDTO>>> GetTokensByUser(int idUser, AuthTokenStatus[]? statuses = null, AuthProvider[]? providers = null) {
statuses ??= [AuthTokenStatus.ACTIVE];


Result<IEnumerable<AuthTokenDTO>> tokens = await Result.Try(() => {
string query = """
SELECT id, idUser, provider, authToken, createdAt, updatedAt, status
FROM crud.auth
WHERE idUser = @idUser
AND status IN (@statuses)
""";

if (providers is { Length: > 0 }) {
query += " AND provider IN (@providers)";
}

return this._context.GetConnection().QueryAsync<AuthTokenDTO>(query, new {
providers,
statuses,
idUser
});
});

if (tokens.IsFailed) {
return Result.Fail("Failed to fetch auth tokens").WithErrors(tokens.Errors);
}

return tokens;
}
public async Task<Result<IEnumerable<AuthTokenDTO>>> GetTokensByUser(int idUser, AuthTokenStatus[]? statuses = null, AuthProvider[]? providers = null) {
statuses ??= [AuthTokenStatus.ACTIVE];


Result<IEnumerable<AuthTokenDTO>> tokens = await Result.Try(() => {
string query = """
SELECT id, idUser, provider, authToken, createdAt, updatedAt, status
FROM crud.auth
WHERE idUser = @idUser
AND status IN (@statuses)
""";

if (providers is { Length: > 0 }) {
query += " AND provider IN (@providers)";
}

return this._context.GetConnection().QueryAsync<AuthTokenDTO>(query, new {
providers,
statuses,
idUser
});
});

if (tokens.IsFailed) {
return Result.Fail("Failed to fetch auth tokens").WithErrors(tokens.Errors);
}

return tokens;
}
Somgör from Human Resources
why not use that fancy EF Core stuff i heard its bad practice to write raw SQL queries but i have no idea abt that stuff yet so :stare:
Indeed
Indeed2mo ago
Different people, different needs Some people need fine-grained queries for their needs It can be better for optimization and suiting one's specific needs without fighting with EFCore
Core
Core2mo ago
If you need something similar to enum just with strings then you could do the following:
c#
public static class SortOrder
{
public const string Ascending = "asc";

public const string Descending = "desc";
}
c#
public static class SortOrder
{
public const string Ascending = "asc";

public const string Descending = "desc";
}
Indeed
Indeed2mo ago
I apologize however I do not believe we understand each other, as I have already mentioned this solution and have also explained my usage and why it might not necessarily work with my current setup I'll try Intellenum for now, but I am open to suggestions for reference:
[Intellenum(typeof(string))]
public partial class CustomerType {
public static readonly CustomerType Basic = new ("Basic");
}
[Intellenum(typeof(string))]
public partial class CustomerType {
public static readonly CustomerType Basic = new ("Basic");
}
Angius
Angius2mo ago
https://github.com/andrewlock/NetEscapades.EnumGenerators
[EnumExtensions]
public enum AuthTokenStatus
{
[Display(Name = "Y")]
Active,
[Display(Name = "N")]
Inactive,
}
[EnumExtensions]
public enum AuthTokenStatus
{
[Display(Name = "Y")]
Active,
[Display(Name = "N")]
Inactive,
}
and use .ToStringFast() instead of .ToString()
Indeed
Indeed2mo ago
Thank you! Looks nice Quick question though, Do you happen to know if there is a way to add a dapper anonymous parameter converter to it so I do not have to map these enums into values before sending them in a query?
Indeed
Indeed2mo ago
Configuring Dapper to work with custom types
In the last post we looked at using custom ID types to help abstract the column type from the domain. This works well until you start trying to load and save entities using an ORM, as the ORM has not way to know how to map a column to a custom type. ORMs provide extension points to allow you to create these mappings. As I tend to favour using Da...