После этого сообщения: Связывание перечислений со строками в C#
Я хотел go дальше, поскольку он не полностью отвечал моим потребностям в Enum, подобном Class, который будет действовать как строка. В итоге я получил решение, которое позволяет мне делать следующее:
string test1 = TestEnum.Analyze; //test1 == "ANALYZE"
string test1bis = (string)TestEnum.Analyze; //test1bis == "ANALYZE"
TestEnum test2 = "ANALYZE"; //test2 == {ANALYZE}
TestEnum test3 = "ANYTHING"; //test3 == null
Как показано ниже в unitTests, все они отлично работают с этим:
public class TestEnum : EnumType<TestEnum>
{
public static TestEnum Analyze { get { return new EnumType<TestEnum>("ANALYZE"); } }
public static TestEnum Test { get { return new EnumType<TestEnum>("TEST"); } }
public static implicit operator TestEnum(string s) => (EnumType<TestEnum>) s;
public static implicit operator string(TestEnum e) => e.Value;
}
Я не могу решить, элегантно это решение или невероятно глупо. Мне кажется, что это, вероятно, ненужное сложное, и я могу испортить гораздо более простое решение, в любом случае оно может кому-то помочь, поэтому я помещаю его здесь.
//for newtonsoft serialization
[JsonConverter(typeof(EnumTypeConverter))]
public class EnumType<T> where T : EnumType<T> , new()
{
public EnumType(string value= null)
{
Value = value;
}
//for servicestack serialization
static EnumType()
{
JsConfig<EnumType<T>>.DeSerializeFn = str =>
{
return (T)str ;
};
JsConfig<EnumType<T>>.SerializeFn = type =>
{
return type.Value;
};
JsConfig<T>.DeSerializeFn = str =>
{
return (T)str;
};
JsConfig<T>.SerializeFn = type =>
{
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<T> ParseJson(string json)
{
return (T)json;
}
public static implicit operator EnumType<T>(string s)
{
if (All.Any(dt => 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 => item.Value).Aggregate((x, y) => $"{x},{y}")}"));
return null;
}
}
public static implicit operator string(EnumType<T> dt)
{
return dt?.Value;
}
public static implicit operator EnumType<T>(T dt)
{
if (dt == null) return null;
return new EnumType<T>(dt.Value);
}
public static implicit operator T(EnumType<T> dt)
{
if (dt == null) return null;
return new T { Value = dt.Value };
}
public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
{
return (string)ct1 == (string)ct2;
}
public static bool operator !=(EnumType<T> ct1, EnumType<T> 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<T> All
=> typeof(T).GetProperties()
.Where(p => p.PropertyType == typeof(T))
.Select(x => (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);
}
}
Вот модульные тесты:
[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<>)
.Assembly
.GetTypes()
.Where(x => x.BaseType?.IsGenericType == true && x.BaseType.GetGenericTypeDefinition() == typeof(EnumType<>))
.Each(x =>
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<TestEnum>
{
(TestEnum)ServiceStack.Text.JsonSerializer.DeserializeFromString("\"ANALYZE\"", typeof(TestEnum)),
"\"ANALYZE\"".FromJson<TestEnum>(),
(TestEnum)Newtonsoft.Json.JsonConvert.DeserializeObject("\"ANALYZE\"", typeof(TestEnum)),
Newtonsoft.Json.JsonConvert.DeserializeObject<TestEnum>("\"ANALYZE\"")
}.Each(testEnum => Assert.AreEqual(testEnum, TestEnum.Analyze));
new List<Test>
{
"{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}".FromJson<Test>(),
(Test)ServiceStack.Text.JsonSerializer.DeserializeFromString("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}", typeof(Test)),
Newtonsoft.Json.JsonConvert.DeserializeObject<Test>("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}"),
(Test)Newtonsoft.Json.JsonConvert.DeserializeObject("{\"PropertyTest\":\"ANALYZE\",\"PropertyString\":\"ANALYZE\"}",typeof(Test))
}.Each(test =>
{
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());
}