0

I was reading the following SO post about Type Safe Enum, and was wondering about the reason to use int internally instead of simply Enum:

So I decided to write the following code:

public readonly struct TypeSafeEnum
{
    private readonly int Value { get; init; } /* implementation detail */
    public readonly string Name { get; init; }
    public static readonly TypeSafeEnum Foo = new TypeSafeEnum { Value = Enum.Foo, Name = nameof(Enum.Foo) };
    public static readonly TypeSafeEnum Bar = new TypeSafeEnum { Value = Enum.Bar, Name = nameof(Enum.Bar) };
    public class Enum
    {
        public const int Foo = 1;
        public const int Bar = 2;
    }
    public static implicit operator int(TypeSafeEnum vr) => vr.Value;
};

Which works well in something like:

bool test(TypeSafeEnum tse)
{
    switch (tse)
    {
        case TypeSafeEnum.Enum.Foo:
        case TypeSafeEnum.Enum.Bar:
            return true;
    }
    return false;
}

Now let's see what happen if we change the implementation detail of this type safe enum using this time an enum internally:

public readonly struct TypeSafeEnum2
{
    private readonly Enum Value { get; init; } /* implementation detail */
    public readonly string Name { get; init; }
    public static readonly TypeSafeEnum2 Foo = new TypeSafeEnum2 { Value = Enum.Foo, Name = nameof(Enum.Foo) };
    public static readonly TypeSafeEnum2 Bar = new TypeSafeEnum2 { Value = Enum.Bar, Name = nameof(Enum.Bar) };
    public enum Enum
    {
        Foo,
        Bar
    }
    public static implicit operator Enum(TypeSafeEnum2 vr) => vr.Value;
};

Now the example above give the following error:

Cannot implicitly convert type 'TypeSafeEnum2.Enum' to 'TypeSafeEnum2'

For reference:

bool test(TypeSafeEnum2 tse)
{
    //switch ((TypeSafeEnum2.Enum)tse)
    switch (tse)
    {
        case TypeSafeEnum2.Enum.Foo:
        case TypeSafeEnum2.Enum.Bar:
            return true;
    }
    return false;
}

Why in the first case switch natively support implicit conversion to int, but does not support implicit conversion to enum in the second case (requires explicit conversion) ?

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
malat
  • 12,152
  • 13
  • 89
  • 158
  • Are you asking for quotes from the language specification, or the language designer's rationale for designing it like this, or what? – Sweeper Sep 02 '21 at 13:11
  • Note that implicit conversions to `bool` is also not supported, but expressions of type `bool` _is_ supported in switch statements. – Sweeper Sep 02 '21 at 13:18
  • 4
    Per the [spec](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/statements#the-switch-statement), "exactly one user-defined implicit conversion [..] must exist from the type of the switch expression to one of the following possible governing types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `string`, or, a nullable type corresponding to one of those types". Conversions to custom enums are out, probably to prevent loops and simplify the logic. – Jeroen Mostert Sep 02 '21 at 13:19
  • Note that you can make this work by adding `public static implicit operator int(TypeSafeEnum2 vr) => (int) vr.Value;` instead, but of course this sort of defeats the purpose of changing the implementation this way. – Jeroen Mostert Sep 02 '21 at 13:23
  • @JeroenMostert no this wont work, since you would also need to `case (int) TypeSafeEnum2.Enum.Foo:` which is even worse ;) – malat Sep 02 '21 at 13:24
  • Oh, right. Well, if you want type-safe enums C# obviously isn't the language of choice. :P – Jeroen Mostert Sep 02 '21 at 13:26

0 Answers0