Casting string to type-safe-enum using user-defined conversion

后端 未结 2 1755
再見小時候
再見小時候 2021-01-19 02:03

In order to use Enum\'s in combination with strings, I implemented a StringEnum class based on https://stackoverflow.com/a/424414/1293385.

However I run into problem

相关标签:
2条回答
  • 2021-01-19 02:15

    You don't need to add another operator. You've already identified the real problem:

    Inspection of the code shows that the instances attribute of the StringEnum class is never filled.

    That's because nothing is ever forcing the DerivedStringEnum class to be initialized. You're never referring to anything which would force it to be initialized. If you do so by adding a static constructor (to avoid type-initialization optimizations) and a static method which is then called to force the initialization, it works fine:

    public class DerivedStringEnum : StringEnum
    {
        // Other members as before.
    
        static DerivedStringEnum()
        {
        }
    
        public static void ForceInit()
        {
        }
    }
    
    class Test
    {
        static void Main()
        {
            string s = "EnumValue1";
            DerivedStringEnum.ForceInit();
            DerivedStringEnum e = (DerivedStringEnum) s;
            Console.WriteLine(e); // EnumValue1
        }
    }
    

    It's not something I'd recommend doing - I dislike it when the state of a base class effectively depends on whether some derived type has been initialized - but it does explain things...

    Note that the answer by Andras works (or at least can work, although I don't think it's guaranteed to) because by invoking the operator declared in the derived type, you might end up initializing the type. You might not though - type initialization can be very lazy. I believe you'd have to actually use a field within the operator (before the call to the base conversion operator) to really force initialization.

    With just the StringEnum operator as per the original question, this line:

    DerivedStringEnum e = (DerivedStringEnum) s;
    

    is compiled to both the custom operator invocation and a cast:

    IL_000d:  ldloc.0
    IL_000e:  call       class StringEnum StringEnum::op_Explicit(string)
    IL_0013:  castclass  DerivedStringEnum
    
    0 讨论(0)
  • 2021-01-19 02:22

    You have to define an explicit cast operator on the derived class as well. The base class is not expected to know how to cast to a derived class.

    Since operators are static they are not inherited - the explicit cast operator is only defined between string and StringEnum. You can do this rather ugly double-cast yourself:

    DerivedStringEnum e = (DerivedStringEnum)(StringEnum)s
    

    Or in your derived class you can put: (edited after @ili pointed out my own oversight)

    public static explicit operator DerivedStringEnum(string name) 
    { 
      return (DerivedStringEnum)(StringEnum)name; 
    } 
    
    0 讨论(0)
提交回复
热议问题