title: Associating Enums with string c#
body: <p>Following This post : <a href="https://stackoverflow.com/questions/630803/associating-enums-with-strings-in-c-sharp/56482413?noredirect=1#comment107635743_56482413">Associating enums with strings in C#</a> </p>
  
  <p>I wanted to go further as it didn't quite fully met my needs for a Enum like Class that would act as string I ended-up with a solution that allows me to do the following: </p>
  
  <pre><code>   string test1 = TestEnum.Analyze;  //test1 == "ANALYZE"
     string test1bis = (string)TestEnum.Analyze; //test1bis == "ANALYZE"
     TestEnum test2 = "ANALYZE";  //test2 == {ANALYZE}
     TestEnum test3 = "ANYTHING"; //test3 == null
  </code></pre>
  
  <p>As seen below in the unitTests all these work fine with this:</p>
  
  <pre><code> public class TestEnum : EnumType&lt;TestEnum&gt; 
      {
          public static TestEnum Analyze { get { return new EnumType&lt;TestEnum&gt;("ANALYZE"); } }
          public static TestEnum Test { get { return new EnumType&lt;TestEnum&gt;("TEST"); } }
  
          public static implicit operator TestEnum(string s) =&gt; (EnumType&lt;TestEnum&gt;) s;
          public static implicit operator string(TestEnum e) =&gt; e.Value;
      }
  </code></pre>
  
  <p>I can't decide if this solution is elegant or incredibly stupid, It seems to me probably unnecessary complex and I might be messing a much easier solution in any case it could help someone so I'm putting this here.</p>
  
  <pre><code> //for newtonsoft serialization
      [JsonConverter(typeof(EnumTypeConverter))]
      public  class EnumType&lt;T&gt;  where T : EnumType&lt;T&gt; , new()
      {
          public EnumType(string value= null)
          {
              Value = value;
          }
  
          //for servicestack serialization
          static  EnumType()
          {
  
                  JsConfig&lt;EnumType&lt;T&gt;&gt;.DeSerializeFn = str =&gt;
                  {
                      return (T)str ;
                  };
                  JsConfig&lt;EnumType&lt;T&gt;&gt;.SerializeFn = type =&gt;
                  {
                      return type.Value;
                  };
  
                  JsConfig&lt;T&gt;.DeSerializeFn = str =&gt;
                  {
                      return (T)str;
                  };
                  JsConfig&lt;T&gt;.SerializeFn = type =&gt;
                  {
                      return type.Value;
                  };
  
  
          }
          protected string Value { get; set; }
  
  
          public static T Parse(string s)
          {
              return (T)s;
  
          }
          public override string ToString()
          {
              return Value;
          }
  
          public static EnumType&lt;T&gt; ParseJson(string json)
          {
              return (T)json;
          }
  
  
          public static implicit operator EnumType&lt;T&gt;(string s)
          {
              if (All.Any(dt =&gt; dt.Value == s))
              {
                  return new T { Value = s };
              }
              else
              {
                  var ai = new Microsoft.ApplicationInsights.TelemetryClient(Connector.tconfiguration);
                  ai.TrackException(new Exception($"Value {s} is not acceptable value for {MethodBase.GetCurrentMethod().DeclaringType}, Acceptables values are {All.Select(item =&gt; item.Value).Aggregate((x, y) =&gt; $"{x},{y}")}"));
                  return null;
              }
          }
  
          public static implicit operator string(EnumType&lt;T&gt; dt)
          {
              return dt?.Value;
          }
  
          public static implicit operator EnumType&lt;T&gt;(T dt)
          {
              if (dt == null) return null;
              return new EnumType&lt;T&gt;(dt.Value);
          }
  
  
          public static implicit operator T(EnumType&lt;T&gt; dt)
          {
              if (dt == null) return null;
              return new T { Value = dt.Value };
          }
  
          public static bool operator ==(EnumType&lt;T&gt; ct1, EnumType&lt;T&gt; ct2)
          {
              return (string)ct1 == (string)ct2;
          }
  
          public static bool operator !=(EnumType&lt;T&gt; ct1, EnumType&lt;T&gt; ct2)
          {
              return !(ct1 == ct2);
          }
  
  
          public override bool Equals(object obj)
          {
              try
              {
                  if(obj.GetType() == typeof(string))
                  {
                      return Value == (string)obj;
                  }
  
                  return Value == obj as T;
              }
              catch(Exception ex)
              {
                  return false;
              }
          }
  
  
  
          public override int GetHashCode()
          {
              return (!string.IsNullOrWhiteSpace(Value) ? Value.GetHashCode() : 0);
          }
  
          public static IEnumerable&lt;T&gt; All
           =&gt; typeof(T).GetProperties()
             .Where(p =&gt; p.PropertyType == typeof(T))
             .Select(x =&gt; (T)x.GetValue(null, null));
  
  
          //for serialisation
          protected EnumType(SerializationInfo info,StreamingContext context)
          {
              Value = (string)info.GetValue("Value", typeof(string));
          }
          public void GetObjectData(SerializationInfo info, StreamingContext context)
          {
              info.AddValue("Value",Value);
  
          }
  
  
      }
  </code></pre>
  
  <p>Here are the unit tests:</p>
  
  <pre><code> [TestFixture]
      public class UnitTestEnum
      {
          Connector cnx { get;set; }
          private class Test
          {
              public TestEnum PropertyTest { get; set; }
              public string PropertyString { get; set; }
          }
  
          [SetUp]
          public void SetUp()
          {
              typeof(EnumType&lt;&gt;)
                 .Assembly
                 .GetTypes()
                 .Where(x =&gt; x.BaseType?.IsGenericType == true &amp;&amp; x.BaseType.GetGenericTypeDefinition() == typeof(EnumType&lt;&gt;))
                 .Each(x =&gt;
                  System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(x.BaseType.TypeHandle)
  
                 );
              cnx = new Connector(); 
          }
          [TearDown]
          public void Clear()
          {
              cnx.Dispose();
          }
          [Test]
          public void EqualsString()
          {
              Assert.AreEqual(TestEnum.Analyze, TestEnum.Analyze);
              Assert.AreEqual(TestEnum.Analyze,"ANALYZE");
              Assert.IsTrue("ANALYZE" == TestEnum.Analyze); 
  
              Assert.IsTrue("ANALYZE".Equals(TestEnum.Analyze));
          }
  
          [Test]
          public void Casts()
          {
  
              string test1 = TestEnum.Analyze;
              string test1bis = (string)TestEnum.Analyze;
              TestEnum test2 = "ANALYZE";
              TestEnum test3 = "NAWAK";
  
              Assert.AreEqual("ANALYZE", test1);
              Assert.AreEqual("ANALYZE", test1bis);
              Assert.IsTrue(test2 == TestEnum.Analyze);
              Assert.IsTrue(test2.Equals(TestEnum.Analyze));
              Assert.AreEqual(test3, null);
  
          }
  
          [Test]
          public void Deserializations()
          {
  
              new List&lt;TestEnum&gt;
              {
                  (TestEnum)ServiceStack.Text.JsonSerializer.DeserializeFromString("\"ANALYZE\"", typeof(TestEnum)),
                  "\"ANALYZE\"".FromJson&lt;TestEnum&gt;(),
                  (TestEnum)Newtonsoft.Json.JsonConvert.DeserializeObject("\"ANALYZE\"", typeof(TestEnum)),
                  Newtonsoft.Json.JsonConvert.DeserializeObject&lt;TestEnum&gt;("\"ANALYZE\"")
              }.Each(testEnum =&gt; Assert.AreEqual(testEnum, TestEnum.Analyze));
  
  
  
  
              new List&lt;Test&gt;
              {
                  "{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}".FromJson&lt;Test&gt;(),
                  (Test)ServiceStack.Text.JsonSerializer.DeserializeFromString("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}", typeof(Test)),
                  Newtonsoft.Json.JsonConvert.DeserializeObject&lt;Test&gt;("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}"),
                  (Test)Newtonsoft.Json.JsonConvert.DeserializeObject("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}",typeof(Test))
              }.Each(test =&gt;
              {
                  Assert.AreEqual(test.PropertyTest, TestEnum.Analyze);
                  Assert.AreEqual(test.PropertyString, "ANALYZE");
              });
  
  
  
  
  
          }
  
          [Test]
          public void Serialisations()
          {
  
  
  
              Assert.AreEqual("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}", new Test { PropertyTest = TestEnum.Analyze, PropertyString = TestEnum.Analyze }.ToJson());
              Assert.AreEqual("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}", Newtonsoft.Json.JsonConvert.SerializeObject(new Test { PropertyTest = TestEnum.Analyze, PropertyString = TestEnum.Analyze }));
              Assert.AreEqual("\"ANALYZE\"", TestEnum.Analyze.ToJson());
              Assert.AreEqual("\"ANALYZE\"", Newtonsoft.Json.JsonConvert.SerializeObject(TestEnum.Analyze));
          }
  
  
          [Test]
          public void TestEnums()
          {
  
              Assert.AreEqual(TestEnum.All.Count(), 2);
              Assert.Contains(TestEnum.Analyze,TestEnum.All.ToList());
              Assert.Contains(TestEnum.Test,TestEnum.All.ToList());
  
          }
  </code></pre>