简体   繁体   中英

String Enum custom class<T> vs Enum with attributes C#

After investigating I concluded what string Enum with attributes is too slow and inconvenient for my purposes.

So my question - is my implementation normal or way redundant and dangerous?=)

public class StringEnum<TChildType> where TChildType: StringEnum<TChildType>, new()
{            
     private readonly Type childType;
     private string _value;
     private readonly HashSet<string> members;

     public string Value
     {
        get { return _value; }
        set
        {
            if (!Contains(value))
                {
                    throw new NotImplementedException(String.Format("Value '{0}' wasnt found in Enum", value));
                }
                _value = value;
            }
        }

        public IEnumerable<string> Values
        {
            get { return members; }
        }
        public bool Contains(string value)
        {
            return members.Contains(value);
        }

        public static IEnumerable<string> GetValues()
        {
            return Service.GetGenericConstProperties<string>(typeof(TChildType));
        }

        public StringEnum()
        {
            childType = typeof(TChildType);
            members = Service.GetGenericStaticProperties<string>(childType).ToHashSet();
            if (members.Count < 2) throw new Exception("Fill Enum!");               
        }

        public static implicit operator StringEnum<TChildType>(string str)
        {
            return new TChildType { Value = str };
        }

        public static implicit operator string(StringEnum<TChildType> source)
        {
            return source != null ? source.Value : null;
        }
    }

Enum Example:

public class PrinterType : StringEnum<PrinterType>
{
   public const string CommonPrinter = "... ...";
   .....
}

How to use:

public class MyPrinter
{
   public StringEnum<PrinterType> PrintType = PrinterType.CommonPrinter;
}

        var list = PrinterType.GetValues().ToList();
        var e = new MyPrinter();
        var q = e.PrintType;
        if (e.PrintType == PrinterType.Ярлыков)
           ...
        if (e.PrintType.Contains("jh"))

or even like backing Field:

        private StringEnum<PrinterType> _type;
        public string Type {... return _type... }

I would change it this way:

public class StringEnum<TChildType> where TChildType : StringEnum<TChildType>, new()
{
    private static readonly HashSet<string> members;
    private static readonly List<string> sortedmembers;

    private string _value;

    public string Value
    {
        get { return _value; }

        protected set
        {
            if (!Contains(value))
            {
                throw new ArgumentException(String.Format("Value '{0}' wasnt found in Enum", value));
            }
            _value = value;
        }
    }

    public static IEnumerable<string> Values
    {
        get { return sortedmembers; }
    }

    public static bool Contains(string value)
    {
        return members.Contains(value);
    }

    static StringEnum()
    {
        sortedmembers = Service.GetGenericConstProperties<string>(typeof(TChildType)); // .ToList() if necessary
        members = new HashSet<string>(sortedmembers);

        if (members.Count < 2) throw new Exception("Fill Enum!");
    }

    public static implicit operator StringEnum<TChildType>(string str)
    {
        return new TChildType { Value = str };
    }

    public static implicit operator string(StringEnum<TChildType> source)
    {
        return source != null ? source.Value : null;
    }

    public static StringEnum<TChildType> Parse(string value)
    {
        return (StringEnum<TChildType>)value;
    }

    public override string ToString()
    {
        return (string)this;
    }

    public override int GetHashCode()
    {
        return StringComparer.Ordinal.GetHashCode(Value);
    }

    public override bool Equals(object obj)
    {
        StringEnum<TChildType> value = obj as StringEnum<TChildType>;

        if (object.ReferenceEquals(value, null))
        {
            return false;
        }

        return StringComparer.Ordinal.Equals(Value, value.Value);
    }
}

An enum , like all value types, is immutable. You can't change it. You can only reassign it. I'm doing the same here. The Value.set is protected, and can be used only internally/by the subclasser of StringEnum<> .

I've implemented the GetHashCode / Equals / ToString .

I've moved all the internal collections to static members, because they are common for all the StringEnum of the same TChildType

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM