새 객체에 할당 할 때 스위치 또는 사전


12

최근에, 나는 문 Dictionaries대신에 1-1 관계를 매핑하는 것을 선호하게되었습니다 Switch. 쓰기가 조금 더 빠르고 정신적으로 처리하기가 더 쉽다는 것을 알게되었습니다. 불행히도 객체의 새 인스턴스에 매핑 할 때 다음과 같이 정의하고 싶지 않습니다.

var fooDict = new Dictionary<int, IBigObject>()
{
    { 0, new Foo() }, // Creates an instance of Foo
    { 1, new Bar() }, // Creates an instance of Bar
    { 2, new Baz() }  // Creates an instance of Baz
}

var quux = fooDict[0]; // quux references Foo

그 구조가 주어지면 CPU 사이클과 3 개의 객체를 만드는 메모리를 낭비하고 생성자가 포함 할 수있는 것을 수행하고 그중 하나만 사용했습니다. 또한 fooDict[0]이 경우 다른 객체를 매핑 하면 Foo의도 한대로 새 인스턴스를 만드는 것이 아니라 동일한 것을 참조하게 됩니다. 해결책은 대신 람다를 사용하는 것입니다.

var fooDict = new Dictionary<int, Func<IBigObject>>()
{
    { 0, () => new Foo() }, // Returns a new instance of Foo when invoked
    { 1, () => new Bar() }, // Ditto Bar
    { 2, () => new Baz() }  // Ditto Baz
}

var quux = fooDict[0](); // equivalent to saying 'var quux = new Foo();'

이것이 너무 혼란스러운 지점에 도달하고 있습니까? 결국에는 놓치기 쉽습니다 (). 아니면 함수 / 표현에 매핑하는 것이 일반적인 관례입니까? 대안은 스위치를 사용하는 것입니다.

IBigObject quux;
switch(someInt)
{
    case 0: quux = new Foo(); break;
    case 1: quux = new Bar(); break;
    case 2: quux = new Baz(); break;
}

어떤 호출이 더 허용됩니까?

  • 빠른 검색 및 더 적은 키워드 (대소 문자 구분)를위한 사전
  • 스위치 : 코드에서 더 일반적으로 발견되며 간접적으로 Func <> 객체를 사용할 필요가 없습니다.

2
람다가 없으면 동일한 키로 조회를 수행 할 때마다 (와 같이) 동일한 인스턴스가 반환됩니다 fooDict[0] is fooDict[0]. 람다와 스위치를 함께 사용하는 경우는 그렇지 않습니다.
ratchet freak

@ratchetfreak 예, 예제를 입력하면서 실제로 이것을 깨달았습니다. 어딘가에 메모 한 것 같습니다.
KChaloux

1
명시 적으로 상수에 넣었다는 것은 생성 된 객체를 변경할 수 있어야한다는 것을 의미합니다. 그러나 언젠가 그것들을 불변으로 만들 수 있다면 객체를 직접 반환하는 것이 가장 좋은 해결책이 될 것입니다. dict를 const 필드에 넣고 전체 응용 프로그램에서 한 번만 생성 비용을 발생시킬 수 있습니다.
Laurent Bourgault-Roy

답변:


7

이것은 팩토리 패턴 에 대한 흥미로운 설명 입니다 . 나는 사전과 람다 표현의 조합을 좋아합니다. 그 컨테이너를 새로운 방식으로 보았습니다.

람다가 아닌 접근 방식이 필요한 것을 제공하지 않는다는 의견에서 언급했듯이 CPU 사이클에 대한 귀하의 질문에 대한 우려를 무시하고 있습니다.

나는 두 가지 접근법 (스위치 대 사전 + 람다)이 좋을 것이라고 생각합니다. 유일한 제한은 사전을 사용하여 리턴 된 클래스를 생성하기 위해 수신 할 수있는 입력 유형을 제한한다는 것입니다.

switch 문을 사용하면 입력 매개 변수에 대한 유연성이 향상됩니다. 그러나 이것이 문제가된다면 메소드 내부에 Dictionary를 랩핑하고 같은 결과를 얻을 수 있습니다.

팀에 새로운 것이면 코드에 주석을 달고 진행 상황을 설명하십시오. 팀 코드 검토를 요청하고 수행 한 작업을 안내하고이를 인식하도록합니다. 그 외에는 괜찮아 보입니다.


불행히도, 약 한 달 전, 내 팀은 나만으로 구성됩니다 (주도 종료). 나는 공장 패턴과의 관련성을 생각하지 않았다. 실제로 깔끔한 관찰입니다.
KChaloux

1
@KChaloux : 당신은 단지 공장 방법 패턴을 사용한다면 물론, 당신이 case 0: quux = new Foo(); break;case 0: return new Foo();것보다 훨씬 더 쉽게 읽을 쓰기에 쉽게 솔직히하고있는{ 0, () => new Foo() }
PDR은

@pdr 이미 코드에서 몇 군데 표시되었습니다. 이 질문에 영감을 준 객체에 대해 팩토리 메소드를 작성해야 할 이유가있을 수 있지만, 스스로 물어 보는 것만으로도 재미있을 것이라고 생각했습니다.
KChaloux

1
@ KChaloux : 스위치 / 케이스를 사전으로 바꾸는 것에 대한 최근의 강박 관념에 관심이 없다고 고백합니다. 자체 방법으로 스위치를 단순화하고 격리하는 것이 더 효과적이지 않은 경우를 아직 보지 못했습니다.
pdr

@pdr 강박 관념은 여기서 사용 하는 강력한 단어입니다. 값 간의 일회성 매핑 처리 방법을 결정할 때 고려해야 할 사항이 더 있습니다. 반복되는 경우에는 창조 방법을 분리하는 것이 최선이라는 데 동의합니다.
KChaloux

7

C # 4.0은 Lazy<T>두 번째 솔루션과 비슷한 클래스를 제공 하지만 "지연된 초기화"를보다 명확하게 외칩니다.

var fooDict = new Dictionary<int, Lazy<IBigObject>>()
{
    { 0, new Lazy(() => new Foo()) }, // Returns a new instance of Foo when invoked
    { 1, new Lazy(() => new Bar()) }, // Ditto Bar
    { 2, new Lazy(() => new Baz()) }  // Ditto Baz
}

오, 몰랐어
KChaloux

오, 멋지다!
Laurent Bourgault-Roy

2
그러나 Lazy.Value가 호출되면 수명 동안 동일한 인스턴스를 사용합니다. Lazy Initialization
Dan Lyons를

물론 그렇지 않으면 게으른 초기화가 아니며 매번 다시 초기화하면됩니다.
Avner Shahar-Kashtan

OP는 매번 새 인스턴스를 생성해야한다고 말합니다. 람다가있는 두 번째 솔루션과 스위치가있는 세 번째 솔루션은 모두 그렇게하지만 첫 번째 솔루션과 Lazy <T> 구현은 그렇지 않습니다.
Dan Lyons 2018

2

독창적으로 나는 가독성이 그들 사이에 같다고 생각합니다. 로 의존성 주입을 수행하는 것이 더 쉽습니다 Dictionary.

를 사용할 때 키가 있는지 확인 Dictionary해야하며 그렇지 않은 경우 폴백을 제공해야합니다.

switch정적 코드 경로 및 Dictionary동적 코드 경로 (항목을 추가하거나 제거 할 수 있는)에 대한 명령문을 선호합니다 . 컴파일러는와 함께 switch할 수없는 정적 최적화를 수행 할 수 있습니다 Dictionary.

흥미롭게도,이 Dictionary패턴은 사람들 이 파이썬에서 가끔하는 일입니다 switch. 파이썬에는 문장 이 없기 때문 입니다. 그렇지 않으면 그들은 if-else 체인을 사용합니다.


1

일반적으로 어느 쪽도 선호하지 않습니다.

이것을 소비하는 것은 무엇이든 사용할 수 Func<int, IBigObject>있습니다. 그런 다음 매핑 소스는 사전 또는 스위치 문이나 웹 서비스 호출 또는 파일 조회 등을 갖는 메소드 일 수 있습니다.

구현에 관해서는 사전이 '하드 코드 사전, 조회 키, 결과 반환'에서 '파일에서 사전로드, 조회 키, 결과 반환'으로보다 쉽게 ​​리팩토링되기 때문에 사전을 선호합니다.

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