정수 식별자를 열거 형에 매핑 할 때의 단점은 무엇입니까?


16

다음과 같은 식별자에 대한 사용자 정의 유형을 작성하려고 생각했습니다.

public enum CustomerId : int { /* intentionally empty */ }
public enum OrderId : int { }
public enum ProductId : int { }

이것에 대한 나의 주요 동기는 실수로 orderItemDetailId를 기대하는 함수에 orderItemId를 전달하는 버그의 종류를 방지하는 것입니다.

열거 형은 일반적인 .NET 웹 응용 프로그램에서 사용하려는 모든 항목과 완벽하게 작동합니다.

  • MVC 라우팅은 잘 작동합니다
  • JSON 직렬화는 잘 작동합니다
  • 내가 생각할 수있는 모든 ORM은 잘 작동합니다.

"지금 왜 안합니까?" 이것들은 내가 생각할 수있는 유일한 단점입니다.

  • 다른 개발자를 혼동시킬 수 있습니다
  • 비 적분 식별자가있는 경우 시스템에 불일치가 발생합니다.
  • 과 같은 추가 캐스팅이 필요할 수 있습니다 (CustomerId)42. 그러나 ORM 및 MVC 라우팅은 일반적으로 열거 형 값을 직접 전달하기 때문에 이것이 문제가 될 것이라고 생각하지 않습니다.

그래서 제 질문은 무엇을 놓치고 있습니까? 이것은 아마도 나쁜 생각이지만 왜 그럴까요?



3
이것은 당신이 주변에 구글 수 있습니다 "microtyping"라고합니다 (예를 들어, 자바에 대한 자세한 내용은 다르지만, 의욕 동일입니다)
QBD

나는 두 가지 부분 답변을 입력 한 다음이 잘못 생각하고 있다는 것을 깨달았으므로 삭제했습니다. "이것은 아마도 나쁜 생각이지만 왜 그럴까요?"에 동의합니다.
user2023861 2019

답변:


7

주로 언급 한 이유로 모든 식별자 종류에 대한 유형 을 만드는 것이 좋습니다 . 적절한 구조체 또는 클래스로 만들면 더 많은 옵션이 제공되므로 형식을 열거 형으로 구현하면 그렇게하지 않습니다.

  • int에 암시 적 변환을 추가 할 수 있습니다. 당신이 그것에 대해 생각할 때, 그것은 다른 방향, int-> CustomerId입니다. 이것은 소비자의 명시적인 확인이 필요한 문제입니다.
  • 허용 가능한 식별자와 허용되지 않는 식별자를 지정하는 비즈니스 규칙을 추가 할 수 있습니다. int가 양수인지 여부를 약하게 검사하는 것이 아닙니다. 때로는 가능한 모든 ID 목록이 데이터베이스에 보관되지만 배포 중에 만 변경됩니다. 그런 다음 적절한 쿼리의 캐시 된 결과에 대해 지정된 ID가 있는지 쉽게 확인할 수 있습니다. 이렇게하면 유효하지 않은 데이터가있는 경우 응용 프로그램이 빠르게 실패 할 수 있습니다 .
  • 식별자에 대한 메소드는 값 비싼 DB 존재 확인을 수행하거나 해당 엔티티 / 도메인 오브젝트를 얻는 데 도움이 될 수 있습니다.

Functional C # : Primitive obsession 기사에서이를 구현하는 방법에 대해 읽을 수 있습니다 .


1
난 당신이 거의 확실하므로 클래스에 있지만, 구조체의 각 INT 포장하지 말 것
JK.

좋은 의견, 나는 대답을 약간 업데이트했습니다.
Lukáš Lánský

3

그것은 영리한 해킹이지만 여전히 의도 된 목적이 아닌 것을위한 기능을 남용하는 해킹입니다. 해킹은 유지 관리 비용이 많이 들기 때문에 다른 결점을 찾을 수 없기 때문에 동일한 문제를 해결하는 더 관용적 인 방법과 비교할 때 상당한 이점 이 있어야합니다 .

관용적 인 방법은 단일 필드로 래퍼 유형 또는 구조체를 만드는 것입니다. 이를 통해보다 명시적이고 관용적 인 방식으로 동일한 유형의 안전성을 제공합니다. 귀하의 제안이 분명히 영리하지만 래퍼 유형을 사용하면 큰 이점이 없습니다.


1
열거 형의 주요 장점은 MVC, 직렬화, ORM 등을 사용하여 원하는 방식으로 "작동하는 것"입니다. 과거에 사용자 정의 유형 (구조 및 클래스)을 만들었고 더 많은 코드를 작성하게됩니다. 이러한 프레임 워크 / 라이브러리가 사용자 정의 유형과 작동하게하려면
default.kramer

직렬화는 어느 쪽이든 투명하게 작동해야합니다. ORM은 어떤 종류의 명시 적 변환을 구성해야합니다. 그러나 이것은 강하게 타이핑 된 언어의 가격입니다.
JacquesB

2

내 POV에서 아이디어가 좋습니다. 관련되지 않은 식별자 클래스에 다른 유형을 부여하고, 유형을 통해 의미를 표현하고 컴파일러가 확인하도록하는 것은 좋은 방법입니다.

.NET 성능 측면에서 어떻게 작동하는지 모르겠습니다. 예를 들어 열거 형 값이 반드시 상자로 표시되어 있습니다. 데이터베이스와 함께 작동하는 OTOH 코드는 어쨌든 I / O 바운드이며 박스형 식별자는 병목 현상이 발생하지 않습니다.

완벽한 세계에서, 식별자는 변하지 않으며 평등에 대해서만 비교할 수 있습니다. 실제 바이트는 구현 세부 사항입니다. 관련이없는 식별자는 호환되지 않는 유형을 가지므로 실수로 다른 식별자를 사용할 수 없습니다. 귀하의 솔루션은 실제로 비용에 맞습니다.


-1

이 작업을 수행 할 수 없으며 열거 형을 미리 정의해야합니다. 따라서 가능한 고객 ID 값의 전체 스펙트럼을 미리 정의하지 않으면 유형이 쓸모가 없습니다.

캐스팅하면 실수로 유형 A id를 유형 B id에 할당하지 못하게하는 주요 목표를 무시하게됩니다. 따라서 열거 형은 목적에 도움이되지 않습니다.

Int32 (또는 Guid)에서 내림차순으로 고객 ID, 주문 ID 및 제품 ID에 대한 유형을 작성하는 것이 도움이 되더라도 질문이 표시됩니다. 이것이 잘못된 이유를 생각할 수 있습니다.

ID의 목적은 식별입니다. 적분 유형은 이미 이것에 완벽합니다. 더 이상 내림차순으로 식별되지 않습니다. 전문화가 요구되거나 요구되는 것은 없으며, 다른 유형의 식별자를 사용하여 세계를 더 잘 표현할 수는 없습니다. OO 관점에서 보면 나쁠 것입니다.

당신의 제안으로 당신은 유형 안전 이상의 것을 원하고, 가치 안전을 원하며 이는 모델링 영역을 넘어서며, 이는 운영상의 문제입니다.


1
아니요. 열거 형은 .NET에서 미리 정의 할 필요가 없습니다. 그리고 요점은 캐스팅이 거의 public ActionResult GetCustomer(CustomerId custId)필요하지 않다는 것입니다. 예를 들어 캐스팅이 필요하지 않습니다. MVC 프레임 워크가 그 가치를 제공 할 것입니다.
default.kramer

2
동의하지 않습니다. 나를 위해, 그것은 OO 관점에서 완벽한 의미가 있습니다. Int32는 의미가 없으며 순전히 "기술적 인"유형입니다. 그러나 객체 식별의 목적을 제공하고 Int32로 구현되는 추상 식별자 유형이 필요합니다 (그러나 길거나 무엇이든 중요하지는 않습니다). ProductId의 구체적인 인스턴스를 식별하는 식별자에서 파생 된 ProductId와 같은 구체적인 전문화가 있습니다. OrderItemId의 값을 ProductId에 할당하는 것은 논리적으로 의미가 없습니다 (오류는 분명합니다). 따라서 유형 시스템이이를 방지 할 수 있습니다.
qbd

1
C #이 열거 형 사용과 관련하여 유연하다는 것을 몰랐습니다. 열거 형이 가능한 값의 열거라는 사실에 익숙한 개발자로서 혼란 스럽습니다. 일반적으로 명명 된 ID의 범위를 지정합니다. 따라서이 유형은 범위가없고 이름이 없다는 의미에서 "거품"입니다. 유형 만 남습니다. 그리고 분명히 유형도 그렇게 안전하지 않습니다. 또 다른 점 :이 예제는 분명히 데이터베이스 응용 프로그램이며 어떤 시점에서 "enum"은 필수 유형 필드에 매핑되어 결국 추정 된 유형을 안전하게 잃게됩니다.
Martin Maat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.