enum to struct

enum은 대부분의 언어에서 지원된다.
enum을 선언할때는 깔끔해 보이지만 enum을 실제로 사용하게 되면 이 방법 밖에 없는지 생각하게 된다.

enum 사용한 예

enum을 구조체로 만들어 지저분한 switch 명령어를 없애 보자.
enum의 원본은 다음과 같다.
using System;

public enum Count
{
    ONE = 1,
    TWO = 2,
    THREE = 3
}

namespace enum_test
{
    class Program
    {
        static int GetNumber(Count count)
        {
            switch (count)
            {
                case Count.ONE:
                    return 1;
                case Count.TWO:
                    return 2;
                case Count.THREE:
                    return 3;
            }

            return 0;
        }

        static void Main(string[] args)
        {
            Console.WriteLine("enum : " + Count.ONE.ToString() + " " + GetNumber(Count.ONE));
        }
    }
}

전형적인 enum 명령어를 사용하고 있는 구문이다.
enum 사용으로 인해 switch 처리가 필요하다.

enum을 구조체로 대체

enum을 구조체로 대체하면 swtich 명령어를 없앨수 있다.
값이 변경 되지 않도록 하기 위해 변수를 "static readonly"로 선언한다.

using System;

public struct Count
{
    public static readonly Count ONE = new Count("ONE", 1);
    public static readonly Count TWO = new Count("TWO", 2);
    public static readonly Count THREE = new Count("THREE", 3);

    public string Name { get; private set; }
    public int Value { get; private set; }

    private Count(string name, int value)
    {
        Name = name;
        Value = value;
    }
}

namespace enum_test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("enum : " + Count.ONE.Name + " " + Count.ONE.Value);
            Count count = Count.TWO;
            Console.WriteLine("enum : " + count.Name + " " + count.Value);
        }
    }
}

구조체 비교

클래스나 구조체에서 비교 연산자(operator ==, operator !=)만 만들면 다음의 워닝이 발생한다.

warning CS0660: `Model.Gender' defines operator == or operator != but does not override Object.Equals(object o)
warning CS0661: `Model.Gender' defines operator == or operator != but does not override Object.GetHashCode()

이때, 워닝이 없이 비교 연산자를 사용해 구조체를 비교 할려면 다음의 사항이 포함 되어야 한다.

1. IEquatable<T> 인터페이스를 상속한다.
2. public override bool Equals(object obj)를 재정의 한다.
3. public override int GetHashCode()를 재정의 한다.
4. public bool Equals(Gender g)를 정의한다.
5. 비교 연산자를 정의한다.

2번과 3번의 Equals, GetHashCode는 워닝을 없애기 위해 필요한 함수이다.
이 함수 내에서 특별한 구현은 하지 않는다.

3번을 구현하지 않으면 다음의 에러가 발생한다.
warning CS0660: `Model.Gender' defines operator == or operator != but does not override Object.Equals(object o)

설명 보다 코드를 보는것이 이해가 빠를 것이다.

    public struct Gender: IEquatable<Gender>
    {
        public static readonly Gender male = new Gender("male", "male_top_orange");
        public static readonly Gender female = new Gender("female", "female_top_orange");

        public string Name { get; private set; }
        public string Upper1 { get; private set; }


        private Gender(string name, string upper1, string upper2)
        {
            Name = name;
            Upper1 = upper1;
        }

        public override int GetHashCode()
        {
            return this.GetHashCode();
        }
        public override bool Equals(object obj)
        {
            return obj is Gender && Equals((Gender)obj);
        }

        public bool Equals(Gender g)
        {
            return (Name == g.Name);
        }

        public static bool operator ==(Gender lhs, Gender rhs)
        {
            return lhs.Equals(rhs);
        }
        public static bool operator !=(Gender lhs, Gender rhs)
        {
            return !(lhs.Equals(rhs.Name));
        }
    }


참조)
https://www.xuehua.us/2018/07/08/蛮牛译馆-unity-c编程优化-枚举/zh-tw/
http://www.huristic.co/blog/2018/1/30/c-advanced-enum-value-types