将枚举与字符串 c# 相关联 [英] Associating Enums with string c#

查看:23
本文介绍了将枚举与字符串 c# 相关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关注这篇文章:关联枚举C#中的字符串

我想更进一步,因为它并没有完全满足我对类似类的枚举的需求,该类将充当字符串我最终得到了一个允许我执行以下操作的解决方案:

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:

   string test1 = TestEnum.Analyze;  //test1 == "ANALYZE"
   string test1bis = (string)TestEnum.Analyze; //test1bis == "ANALYZE"
   TestEnum test2 = "ANALYZE";  //test2 == {ANALYZE}
   TestEnum test3 = "ANYTHING"; //test3 == null

如下面的 unitTests 所示,所有这些都可以正常工作:

As seen below in the unitTests all these work fine with this:

 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;
    }

我无法确定这个解决方案是优雅还是非常愚蠢,在我看来这可能是不必要的复杂,而且我可能会弄乱一个更简单的解决方案,它可以帮助某人,所以我把它放在这里.

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.

 //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());

        }

推荐答案

优雅的代码通常被描述为简单、干净、简洁、意图明确且性能最佳,我在这里没有看到任何这些特征,特别令人费解的是而不是按预期使用简单的 C# 枚举,而是将它们包装在具有隐式转换和自定义序列化处理的通用基类中,用于不同的 JSON 序列化库(这不太可能在其他序列化库/格式中工作),并且添加了所有额外的人工复杂性甚至不清楚所有样板的好处或目的是什么?

Elegant code is typically described as simple, clean, terse with clear intent and optimally performant, I'm not seeing any of these traits here which is especially convoluted as instead of using simple C# Enum's as intended they're wrapped in a generic base class with implicit casts and custom serialization handling for different JSON Serialization libraries (that's unlikely to work in other serialization libraries/formats) and with with all the additional artificial complexity added it's not even clear what the benefit or purpose of all the boilerplate is?

淹没在大量样板文件中的代码增加了维护负担并抑制了重构,因为没有人会知道代码的预期意图或目的是什么&为什么没有采用更简单的天真的解决方案.

Code that's drowned in so much boilerplate increases the maintenance burden and inhibits refactoring as no one else is going to know what the desired intent or purpose of the code is meant to be & why simpler naive solutions weren't adopted instead.

如果您只想对代码中使用的符号名称使用不同的 Wire Serialization 格式(IMO 应该有充分的理由不同),您可以使用 [EnumMember] Serialization属性:

If you just want to have a different Wire Serialization format to the Symbol name used in code (which IMO should have a good reason for being different), you can just use the [EnumMember] Serialization attribute:

[DataContract]
public enum TestEnum 
{
    [EnumMember(Value = "ANALYZE")]
    Analyze,
    [EnumMember(Value = "TEST")]
    Test,
}

否则我会放弃使用枚举并返回使用字符串常量,它更简单、更快、内存效率高并且适用于所有序列化库,无需自定义序列化技巧:

Otherwise I'd dispense with using Enums and go back to using string constants, which are simpler, faster, memory efficient and works in all Serialization libraries without custom serialization hacks:

public static class MyConstants
{
    public const string Analyze = "ANALYZE";
    public const string Test = "TEST";
}

这篇关于将枚举与字符串 c# 相关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆