C #에서 매직 메소드가 구현 된 이유는 무엇입니까?


16

C #에서는 인터페이스로 백업하지 않고 이러한 모든 마법 메서드가 나타나는 것을 시작했습니다. 이것이 왜 선택 되었습니까?

설명하겠습니다.

객체가 구현 된 경우 이전 C #에서, IEnumerable인터페이스, 그것은 자동으로 반복 가능한 일 것이다 foreach루프. 그것은 인터페이스에 의해 백업되기 때문에 나에게 의미가 있으며, Iterator반복되는 클래스 내에서 내 자신의 기능 을 가지고 있다면 마술처럼 다른 것을 의미 할 것이라고 걱정하지 않고 그렇게 할 수 있습니다.

분명히, (언제나 확실하지는 않지만) 이러한 인터페이스는 더 이상 필요하지 않습니다. 올바른 이름 변환이 필요합니다.

또 다른 예는 몇 가지 특정 속성을 가진 정확히 이름이 지정된 메서드를 사용하여 객체를 대기 가능하게 만드는 것 GetAwaiter입니다.

이 "매직"을 정적으로 백업 IEnumerable하거나 INotifyPropertyChanged백업 하는 것처럼 인터페이스를 만들지 않겠습니까?

내가 의미하는 바에 대한 자세한 내용 :

http://blog.nem.ec/2014/01/01/magic-methods-c-sharp/

마술 방법의 장단점은 무엇이며 온라인에서 이러한 결정이 내려진 이유를 찾을 수있는 곳이 있습니까?


4
폐쇄하고 싶지 않다면 왜 "매직이 나쁜지"에 대한 개인적인 의견을 편집해야합니다.
DougM

2
Anders Hejlsberg가 왜 그랬는지 알고 싶다면 물어봐야합니다. 내가 왜 그런 짓을했는지 말해 줄 수 있으며 앞으로 호환성을위한 것입니다. 확장 메소드를 사용하면 기존 유형에 메소드를 "가짜"추가 할 수 있지만 확장 인터페이스는 없습니다. async/에 대한 인터페이스가 필요한 경우 await.NET 4.5 이후에 작성된 코드로만 작동하며 실행 가능한 대상이 될 수 있습니다. 그러나 메소드 호출로 순전히 구문 변환 await하면 사실 후에 기존 유형 에 기능을 추가 할 수 있습니다 .
Jörg W Mittag

2
이것은 기본적으로 적용되는 객체 지향입니다. 객체가 적절한 메시지에 응답하는 한 올바른 유형으로 간주됩니다.
Jörg W Mittag

7
당신의 "이전"과 "지금"은 거꾸로되어 있습니다. 매직 메소드는 foreach처음에 루프백을 위한 기본 기능으로 구현되었습니다 . 이 결코 오브젝트 구현하기위한 요구 사항 없었다 IEnumerable위한 foreach작업에. 그렇게하는 것이 관습이었습니다.
Jesse C. Slicer

2
@gbulmer이 내가로부터 아이디어를 얻는 기억합니다 어디 : blogs.msdn.com/b/ericlippert/archive/2011/06/30/... (그리고 낮은 정도에 ericlippert.com/2013/07/22/... )를
제시 C. 슬라이서 2

답변:


16

일반적으로 동일한 방법으로 작동하는 인터페이스를 만들 수없는 경우 "매직 방법"이 사용됩니다.

foreachC # 1.0에서 처음 소개 되었을 때 (이 동작은 최근에는 아무것도 아님), 제네릭이 없기 때문에 마술 방법을 사용해야했습니다. 옵션은 기본적으로 다음과 같습니다.

  1. 비 일반 사용 IEnumerableIEnumerator와 그 일 object권투 값 유형을 의미들. ints 목록과 같은 것을 반복하는 것은 매우 빠르며 가비지 박스 값을 많이 생성해서는 안되기 때문에 이것은 좋은 선택이 아닙니다.

  2. 제네릭을 기다립니다. 이것은 아마도 .Net 1.0 (또는 적어도 foreach)을 3 년 이상 지연시키는 것을 의미 합니다.

  3. 마법의 방법을 사용하십시오.

따라서 그들은 옵션 # 3을 선택했으며 .Net 2.0 이후로도 이전 버전과의 호환성 이유로 인해 우리와 함께 머물 렀 IEnumerable<T>습니다.


컬렉션 이니셜 라이저는 각 컬렉션 유형마다 다르게 보일 수 있습니다. 비교 List<T>:

public void Add(T item)

그리고 Dictionary<TKey, TValue>:

public void Add(TKey key, TValue value)

에 대한 첫 번째 형식 만 지원 List<T>하고 두 번째에 대해서만 지원하는 단일 인터페이스를 가질 수 없습니다 Dictionary<TKey, TValue>.


LINQ 메소드는 일반적으로 확장 메소드로 구현되므로 (을 구현하는 모든 유형에 대해 LINQ to Object의 단일 구현 만 IEnumerable<T>가능함) 인터페이스를 사용할 수 없습니다.


들어 awaitGetResult()방법은 반환하거나 수 있습니다 void또는 어떤 종류 T. 다시 말하지만, 둘 다 처리 할 수있는 단일 인터페이스를 가질 수 없습니다. await부분적으로 인터페이스 기반 이지만 , 대기자는 구현해야 INotifyCompletion하고 구현할 수도 있습니다 ICriticalNotifyCompletion.


1
C # 1.0에 대해 "옵션 # 3"을 선택 했습니까? 내 기억은 옵션 1이었다. 내 기억은 C # 컴파일러가 '자동 박싱'과 '자동 언 박싱'을 수행했기 때문에 C #이 Java보다 우월하다고 주장했다. C #은 foreach 가 Java보다 부분적으로 훨씬 뛰어나다 는 코드를 만들었습니다 .
gbulmer

1
foreachC # 1.2에 대한 설명서 (C # 1.0에 대한 MSDN에는 아무것도 없음)에 나와있는 foreach"구현 IEnumerable유형 또는 GetEnumerator메서드 를 선언하는 유형으로 평가" 의 표현에 따르면 상자의 의미를 잘 모르겠습니다. C #에서는 항상 명시 적입니다.
svick

1
@gbulmer 그리고 2001 년 12 월부터 C #에 대한 ECMA 사양 (C # 1.0을 의미해야 함)은 다음과 같이 말합니다 (§15.8.4). 다음 기준을 모두 충족하여 수집 패턴을 구현합니다 […]”.
svick

1
@svick 은 시퀀스 요소에 foreach(T x in sequence)명시 적 캐스트를 적용 T합니다. 따라서 시퀀스가 ​​일반 IEnumerable이고 T값 유형 인 경우 코드에 명시적인 캐스트가 작성되지 않은 상태로 개봉됩니다. C #의 못생긴 부분 중 하나입니다.
코드 InChaos

@CodesInChaos "Auto-unboxing"은 꽤 일반적으로 들리지만이 특정 기능을 참조한다는 것을 알지 못했습니다. (나는 우리가 이야기하고 있었기 때문에 내가 있어야한다고 생각합니다 foreach.)
svick
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.