ardalis / ardalis/SmartEnum

Feature Request: Support non-reflection based FromValue/FromName methods

Open
#104 1 comment 2 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
2.4k
Forks
184
PR merge metrics
No merged PRs in 30d

Description

I have a subclass of `SmartEnum` that defines implementations for bitwise OR and AND so that I can treat the enum value as flags. Here's a minimal implementation:
```csharp
public class MyEnum : SmartEnum
{
protected MyEnum(string name, int value) : base(name, value) { }
public static MyEnum A { get; } = new MyEnum(nameof(A), 0);
public static MyEnum B { get; } = new MyEnum(nameof(B), 1);
public static MyEnum C { get; } = new MyEnum(nameof(C), 2);
public static MyEnum D { get; } = new MyEnum(nameof(D), 4);

public static bool operator true(MyEnum val) => val != None;
public static bool operator false(MyEnum val) => val == None;

public static bool operator ==(MyEnum a, MyEnum b)
{
return (a & b) == a;
}

public static bool operator !=(MyEnum a, MyEnum b)
{
return (a | b) == a;
}

public static Restriction operator &(MyEnum a, MyEnum b)
{
return new MyEnum(CombineName(a,b), a.Value & b.Value);
}

public static MyEnum operator |(MyEnum a, MyEnum b)
{
return new MyEnum(CombineName(a, b), a.Value | b.Value);
}
private static string CombineName(Restriction a, Restriction b)
{
var delimiter = "|";
var aNames = a.Name.Split(delimiter);
var bNames = b.Name.Split(delimiter);

var allNames = aNames.Union(bNames);
return string.Join(delimiter, allNames);
}
}

public class MyEnumTest
{
[Fact] // this test fails
public void FromValue_ShouldSucceed_WhenBitwiseOperatorsApplied()
{
var val = MyEnum.A | MyEnum.B;
var result = MyEnum.FromValue(val.Value);
Assert.Equal(restrictions, val);
}
}
```

The `SmartEnum` implementation seemingly uses reflection to lookup what fields are instances of `MyEnum`. Since I can't add the dynamically created instances from my overloaded operators to the class using reflection, I would need the underlying `SmartEnum` class to implement a different approach to looking up those enum values and also allow subclasses to register new instances dynamically to the lookup collection.

In addition, it would be nice to not have to implement bitwise operators for the use of flags. I saw that there's an open pull request with `SmartFlagsEnum` that might be of some use.

For now, in my application I will simply accept that the `FromValue` and `FromName` methods will fail and instead build any abstractions on `TryFromValue` and `TryFromName`, although that's not ideal for my use case.

Contributor guide

Open the contributing guide

Research direction

Start with the SmartEnum implementation and trace how FromValue, FromName, TryFromValue, and TryFromName discover instances. Review the mentioned SmartFlagsEnum pull request for related context; done should support the requested non-reflection lookup and dynamic registration, with flag values handled as described.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.