상속을 통해 열거 형 확장


85

나는 이것이 enum의 개념에 반한다는 것을 알고 있지만 C # / Java에서 enum을 확장 할 수 있습니까? 열거 형에 새 값을 추가하는 의미에서 "확장"을 의미하지만 기존 열거 형에서 상속하는 OO 의미에서도 마찬가지입니다.

자바에서는 가능하지 않다고 생각합니다. 꽤 최근에 나온 것입니다 (Java 5?). C #은 미친 짓을하고 싶어하는 사람들을 더 관대 해 보이기 때문에 어떤 식 으로든 가능할 것이라고 생각했습니다. 아마도 리플렉션을 통해 해킹 당할 수 있습니까? (실제로 모든 방법을 사용하는 것은 아닙니다)?

나는 주어진 방법을 구현하는 데 반드시 관심이있는 것은 아니며, 그것이 나에게 일어 났을 때 호기심을 불러 일으켰습니다. :-)


이것이 귀하의 질문에 대답합니까? Enum "Inheritance"
T.Todua

답변:


103

Enum을 확장 할 수없는 이유는 다형성 문제로 이어지기 때문입니다.

값이 A, B 및 C 인 열거 형 MyEnum이 있고이를 MyExtEnum 값으로 D 값으로 확장한다고 가정합니다.

메소드가 예를 들어 매개 변수로 myEnum 값을 어딘가에 예상한다고 가정하십시오. 하위 유형이기 때문에 MyExtEnum 값을 제공하는 것이 합법적이어야하지만 이제 값이 D 인 것으로 밝혀지면 무엇을 하시겠습니까?

이 문제를 해결하기 위해 열거 형을 확장하는 것은 불법입니다.


4
사실 그 이유는 단순히 말이되지 않기 때문입니다. 언급 한 문제, 즉 예상하지 못한 상수를받는 클라이언트 코드는 현재 구현에 여전히 존재합니다. 사실 컴파일러는 케이스 switch를 제공 default하거나 예외를 던지지 않고는 열거 형 값을 허용하지 않습니다 . 그리고 그렇게하더라도 런타임시 열거 형은 별도의 컴파일에서 올 수 있습니다
Raffaele 2014 년

@Raffaele 방금 이것을 시도했으며 적어도 Java 7에서는 default케이스 또는 던지지 않고 열거 형을 켤 수 있습니다 .
Dathan

@Dathan 당신이 확실히 옳습니다! 쓰여진대로 그것은 단순히 잘못된 것입니다. 제거해야할까요? switch지역의 이니셜과 같은 필수 값을 제공하기 위해 a 를 사용 하거나return
Raffaele 2014 년

3
이건 개인적인 게 아니야, 릭. 그러나 이것은 거의 최악의 이유입니다! 다형성 및 열거 ...DayOfWeek a = (DayOfWeek) 1; DayOfWeek b = (DayOfWeek) 4711; Console.WriteLine(a + ", " + b);
Bitterblue

41

내장 된 열거 형으로 충분하지 않은 경우, 구식 방식으로 수행하고 직접 만들 수 있습니다. 예를 들어 설명 필드와 같은 추가 속성을 추가하려는 경우 다음과 같이 할 수 있습니다.

public class Action {
    public string Name {get; private set;}
    public string Description {get; private set;}

    private Action(string name, string description) {
        Name = name;
        Description = description;
    }

    public static Action DoIt = new Action("Do it", "This does things");
    public static Action StopIt = new Action("Stop It", "This stops things");
}

그런 다음 다음과 같이 열거 형으로 처리 할 수 ​​있습니다.

public void ProcessAction(Action a) {
    Console.WriteLine("Performing action: " + a.Name)
    if (a == Action.DoIt) {
       // ... and so on
    }
}

트릭은 생성자가 비공개 (또는 상속하려는 경우 보호됨)이고 인스턴스가 정적인지 확인하는 것입니다.


나는 C # 사람이 아니지만 거기에 약간의 최종 (또는 봉인 / 상수 / 무엇이든)을 원하지 않습니까?
Tom Hawtin-tackline

1
나는 그렇게 믿지 않는다. 또는 최소한 새로운 "열거 형"값을 추가하기 위해이 클래스에서 상속하려는 상황에는 적합하지 않습니다. 최종 및 봉인은 상속 IIRC를 방지합니다.
alastairs

4
@alastairs 나는 그가 수업보다는 줄에 추가 final하는 것을 의미했다고 생각 public static Action DoIt = new Action("Do it", "This does things");합니다.
분쇄

1
추가하여에서 readonly와 같이 ala :public static readonly Action DoIt = new Action("Do it", "This does things");
ErikE

40

잘못된 방향으로 가고 있습니다. 열거 형의 하위 클래스에는 항목 이 더 적습니다 .

의사 코드에서 다음을 생각하십시오.

enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat };  // (not valid C#)

동물을 받아 들일 수있는 모든 방법은 포유류를 받아 들일 수 있어야하지만 그 반대는 아닙니다. 서브 클래 싱은 더 일반적인 것이 아니라 더 구체적으로 만드는 것입니다. 이것이 "객체"가 클래스 계층 구조의 루트 인 이유입니다. 마찬가지로, 열거 형이 상속 가능한 경우 열거 형 계층의 가상 루트에는 가능한 모든 기호가 있습니다.

그러나 아니요, C # / Java는 하위 열거 형 AFAICT를 허용하지 않습니다.하지만 때때로 정말 유용 할 것입니다. 아마도 그들은 인턴 심볼 (예 : Lisp) 대신에 Int (예 : C)로 Enum을 구현하기로 선택했기 때문일 것입니다. (위에서 (Animal) 1은 무엇을 나타내고, (Mammal) 1은 무엇을 나타내며, 동일한 값입니까?)

그러나 이것을 제공하는 자신의 열거 형 클래스 (다른 이름으로)를 작성할 수 있습니다. C # 속성을 사용하면 멋지게 보일 수도 있습니다.


3
흥미로운 분석. 이런 식으로 생각하지 못했습니다!
Nerrve

Intersting하지만 잘못된 것 같습니다. 하위 클래스에 더 적은 유형이 있어야 함을 암시하는 것은 동물 분류 트리 측면에서 의미가 있지만 코드 측면에서는 의미가 없습니다. 코드에서 하위 항목을 만들 때 메서드가 적지 않습니다. 멤버 변수는 적지 않습니다. 당신의 주장은 동물 분류와 마찬가지로 소프트웨어에 적용되지 않는 것 같습니다.
Kieveli 2013 년

4
@Kieveli, 분석이 잘못되었습니다. 멤버를 추가해도 가능한 값 집합에 추가하는 것과 개체에 영향을주지 않습니다. 이것은 Ken이 만든 것이 아닙니다. 왜 이런 식으로 작동하는지 설명하는 명확하고 정확한 컴퓨터 과학 규칙이 있습니다. 공분산 및 반공 변성을 검색해보십시오 (학업 적 자위뿐만 아니라 함수 서명 및 컨테이너와 같은 규칙을 이해하는 데 도움이됩니다).
jwg

@Kieveli 'StreamWriter'클래스가 있다고 가정합니다 (스트림 가져 오기-스트림 쓰기). 'TextWriter : StreamWriter'(스트림 가져 오기-텍스트 쓰기)를 만듭니다. 이제 'HtmlWriter : TextWriter'를 만듭니다 (스트림 가져 오기-예쁜 html 작성). 이제 HtmlWriter에는 분명히 더 많은 멤버, 메서드 등이 있습니다. 이제 사운드 카드에서 스트림을 가져 와서 HtmlWriter를 사용하여 파일에
기록해보십시오.

이 예제는 인위적이며 확장 클래스에 MORE 열거 형 값이 있어서는 안된다는 것을 증명하지 않습니다. enum VehicalParts {License, Speed, Capacity}; enum CarParts {SteeringWheel, Winshield}; + Vehical이 가지고있는 모든 것
Bernoulli Lizard

12

열거 형은 가능한 모든 값의 열거 형을 나타내야하므로 확장은 아이디어에 어긋납니다.

그러나 Java (그리고 아마도 C ++ 0x)에서 할 수있는 것은 열거 형 클래스 대신 인터페이스를 갖는 것입니다. 그런 다음 기능을 구현하는 열거 형에 표준 값을 입력합니다. 분명히 당신은 java.util.EnumSet 등을 사용하지 않습니다. 이것은 JDK7에 있어야하는 "더 많은 NIO 기능"에서 취해진 접근 방식입니다.

public interface Result {
    String name();
    String toString();
}
public enum StandardResults implements Result {
    TRUE, FALSE
}


public enum WTFResults implements Result {
    FILE_NOT_FOUND
}

4

당신은 실행시에 기존의 열거에서 레이블과 값을 검색 할 .NET 반사를 사용할 수 있습니다 ( Enum.GetNames()그리고 Enum.GetValues()당신이 사용하는 것과 두 가지 특정 방법입니다) 그리고 이러한 요소를 더한 새로운 사람과 새로 만들 코드 주입을 사용. 이것은 "기존 열거 형에서 상속"과 다소 유사 해 보입니다.


2

열거 형을 추가하는 것은 소스 코드로 돌아가서 편집하는 경우에 수행하는 매우 일반적인 작업입니다. 다른 방법 (가능한 경우 상속 또는 반영)이 다시 돌아와 라이브러리를 업그레이드 할 때 타격을 입힐 수 있습니다. 그들은 동일한 열거 형 이름 또는 동일한 열거 형 값 을 도입했습니다 . 정수 숫자가 바이너리 인코딩과 일치하는 저수준 코드를 많이 보았습니다. 여기서 문제가 발생합니다.

이상적으로 열거 형을 참조하는 코드는 같음 (또는 스위치)으로 작성되어야하며, 열거 형 집합이 const가 될 것으로 예상하지 않음으로써 미래의 증거가되어야합니다.


2

Base 클래스 의미에서 확장을 의미한다면 Java에서 ... 아니요.

그러나 그것이 의미하는 경우 속성과 메서드를 갖도록 열거 형 값을 확장 할 수 있습니다.

예를 들어 다음은 대괄호 열거 형을 사용합니다.

class Person {
    enum Bracket {
        Low(0, 12000),
        Middle(12000, 60000),
        Upper(60000, 100000);

        private final int low;
        private final int high;
        Brackets(int low, int high) {
            this.low = low;
            this.high = high;
        }

        public int getLow() {
            return low;
        }

        public int getHigh() {
            return high;
        }

        public boolean isWithin(int value) {
           return value >= low && value <= high;
        }

        public String toString() {
            return "Bracket " + low + " to " + high;
        }
    }

    private Bracket bracket;
    private String name;

    public Person(String name, Bracket bracket) {
        this.bracket = bracket;
        this.name = name;
    }

    public String toString() {
        return name + " in " + bracket;
    }        
}

이것은 .NET의 값 유형 (구조체)처럼 들립니다. 나는 당신이 자바에서 이것을 할 수 있다는 것을 몰랐다.
alastairs 2011 년

2

다른 사람이 이것을 언급하는 것을 보지 못했지만 열거 형의 서수 값이 중요합니다. 예를 들어, 데이터베이스에 열거 형을 저장할 때 grails에서는 서수 값을 사용합니다. 어떻게 든 열거 형을 확장 할 수 있다면 확장의 서수 값은 무엇입니까? 여러 곳에서 확장했다면 어떻게 이러한 서수에 대한 질서를 유지할 수 있습니까? 서수 값의 혼돈 / 불안정성은 언어 디자이너가 이것을 건드리지 않은 또 다른 이유 일 것입니다.

언어 디자이너라면 또 다른 어려움은 모든 열거 형 값을 반환해야하는 values ​​() 메서드의 기능을 어떻게 보존 할 수 있는지입니다. 이것을 무엇에 호출하고 모든 가치를 어떻게 모을 것인가?



0

열거 형에서 상속 / 확장 할 수 없으며 속성 을 사용 하여 설명선언 할 수 있습니다 . 정수 값을 찾고 있다면 내장되어 있습니다.


0

흠-내가 아는 한, 이것은 할 수 없습니다. 열거 형은 디자인 타임에 작성되며 프로그래머의 편의를 위해 사용됩니다.

코드가 컴파일 될 때 열거 형의 이름이 동등한 값으로 대체되어 열거 형 개념과 확장 기능이 제거 될 것입니다.


0

기존 값의 조합 인 C # 열거 형에 값을 추가하고 싶습니다. 예를 들어 (이것은 내가 원하는 것입니다) :

AnchorStyles는 다음과 같이 정의됩니다.

public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, }

그리고 AnchorStyles.BottomRight = Right + Bottom을 추가하고 싶습니다.

my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;

그냥 말할 수 있어요

my_ctrl.Anchor = AnchorStyles.BottomRight;

이것은 위에서 언급 한 문제를 일으키지 않으므로 가능하다면 좋을 것입니다.


0

얼마 전에 나는 이와 같은 일을하고 싶었고 enum 확장이 많은 기본 개념을 부추 기는 것을 발견했습니다 ... (다형성뿐만 아니라)

그러나 enum이 외부 라이브러리에서 선언 된 경우 여전히해야 할 수 있으며이 enum 확장을 사용할 때 특별한주의를 기울여야합니다.

public enum MyEnum { A = 1, B = 2, C = 4 }

public const MyEnum D = (MyEnum)(8);
public const MyEnum E = (MyEnum)(16);

func1{
    MyEnum EnumValue = D;

    switch (EnumValue){
      case D:  break;
      case E:  break;
      case MyEnum.A:  break;
      case MyEnum.B:  break;
   }
}

0

자바에 관한 한 열거 형에 요소를 추가하면 하위 클래스가 아닌 슈퍼 클래스가 효과적으로 생성되기 때문에 허용되지 않습니다.

중히 여기다:

 enum Person (JOHN SAM}   
 enum Student extends Person {HARVEY ROSS}

다형성의 일반적인 사용 사례는 다음과 같습니다.

 Person person = Student.ROSS;   //not legal

그것은 분명히 잘못된 것입니다.


0

매우 로컬 / 한 번 사용하려는 경우 임시 / 로컬 해결 방법 :

enum Animals { Dog, Cat }
enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat,  MyOther}
// BUT CAST THEM when using:
var xyz = AnimalsExt.Cat;
MethodThatNeedsAnimal(   (Animals)xyz   );

모든 답변보기 : Enum "Inheritance"

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.