우선, 좋은 질문입니다. 나는 맹목적으로 "모범 사례"를 받아들이지 않고 유틸리티에 초점을두고 있습니다. +1입니다.
전에 그 가이드를 읽었습니다. 당신은 그것에 대해 무언가를 기억해야합니다-그것은 단지 프로그래밍 방법을 알고 있지만 C # 일을하는 방법에 익숙하지 않은 C # 초보자를위한 가이드 일뿐입니다. 그것은 일반적으로 일이 이미 수행되는 방법을 설명하는 페이지이므로 규칙 페이지만큼 중요하지 않습니다. 그리고 그들은 이미 모든 곳에서 이런 식으로 수행되었으므로 일관성을 유지하는 것이 좋습니다.
당신의 질문에 대답하면서 요점을 알려 드리겠습니다.
우선, 인터페이스가 무엇인지 이미 알고 있다고 가정합니다. 델리게이트의 경우, 메소드에 대한 유형이 지정된 포인터와 this해당 메소드 의 인수를 나타내는 오브젝트에 대한 선택적 포인터를 포함하는 구조라고 말하는 것으로 충분합니다 . 정적 메소드의 경우 후자의 포인터는 널입니다.
또한 멀티 캐스트 델리게이트도 있는데, 델리게이트와 유사하지만 이러한 구조 중 일부가 할당되어있을 수 있습니다 (멀티 캐스트 델리게이트에서 Invoke를 한 번 호출하면 할당 된 호출 목록의 모든 메소드가 호출 됨).
이벤트 디자인 패턴의 의미는 무엇입니까?
이는 C #에서 이벤트를 사용하는 것을 의미합니다 (이 매우 유용한 패턴을 간결하게 구현하기위한 특수 키워드가 있음). C #의 이벤트는 멀티 캐스트 대리인이 제공합니다.
이 예제와 같이 이벤트를 정의 할 때 :
class MyClass {
// Note: EventHandler is just a multicast delegate,
// that returns void and accepts (object sender, EventArgs e)!
public event EventHandler MyEvent;
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
컴파일러는 실제로 이것을 다음 코드로 변환합니다.
class MyClass {
private EventHandler MyEvent = null;
public void add_MyEvent(EventHandler value) {
MyEvent += value;
}
public void remove_MyEvent(EventHandler value) {
MyEvent -= value;
}
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
그런 다음 다음 을 수행하여 이벤트 를 구독하십시오.
MyClass instance = new MyClass();
instance.MyEvent += SomeMethodInMyClass;
어떤 컴파일
MyClass instance = new MyClass();
instance.add_MyEvent(new EventHandler(SomeMethodInMyClass));
C # (또는 일반적으로 .NET)에서 이벤트입니다.
델리게이트를 사용하면 컴포지션이 어떻게 쉬운 지 알 수 있습니까?
이것은 쉽게 입증 될 수 있습니다 :
전달할 조치 세트에 의존하는 클래스가 있다고 가정하십시오. 인터페이스에서 이러한 동작을 캡슐화 할 수 있습니다.
interface RequiredMethods {
void DoX();
int DoY();
};
그리고 클래스에 액션을 전달하려는 사람은 먼저 해당 인터페이스를 구현해야합니다. 또는 다음 수업에 따라 삶을 더 편하게 만들 수 있습니다 .
sealed class RequiredMethods {
public Action DoX;
public Func<int> DoY();
}
이렇게하면 호출자는 RequiredMethods의 인스턴스를 만들고 런타임에 대리자에게 메서드를 바인딩하기 만하면됩니다. 이것은 이다 일반적으로 쉽게.
이런 일을하는 것은 올바른 상황에서 매우 유익합니다. 생각해보십시오-실제로 관심이있는 모든 것이 구현을 전달하는 것만으로 인터페이스에 의존하는 이유는 무엇입니까?
관련 메소드 그룹이있을 때 인터페이스 사용의 이점
인터페이스에는 일반적으로 명시적인 컴파일 타임 구현이 필요하므로 인터페이스를 사용하는 것이 좋습니다. 이것은 새로운 클래스를 생성한다는 것을 의미합니다.
단일 패키지에 관련 메소드 그룹이있는 경우 코드의 다른 부분에서 해당 패키지를 재사용 할 수있게하는 것이 좋습니다. 따라서 일련의 델리게이트를 작성하는 대신 단순히 클래스를 인스턴스화 할 수 있으면 더 쉽습니다.
클래스에 구현이 하나만 필요한 경우 인터페이스 사용의 이점
앞에서 언급했듯이 인터페이스는 컴파일 타임에 구현됩니다. 즉, 델리게이트를 호출하는 것 (보다 간접적 인 수준)보다 더 효율적입니다.
"하나의 구현"은 잘 정의 된 단일 장소가 존재하는 구현을 의미 할 수 있습니다.
그렇지 않으면 프로그램의 어느 곳에서나 구현이 메소드 서명 과 일치하기 만합니다. 메소드는 특정 인터페이스를 명시 적으로 구현하는 클래스에 속하기보다는 예상 서명 만 준수하면되기 때문에 유연성이 향상됩니다. 그러나 이러한 유연성은 비용이 많이 들며 실제로 사고 가능성을 최소화하기 때문에 대부분의 명시 성을 원하기 때문에 Liskov 대체 원칙을 위반합니다 . 정적 입력과 같습니다.
이 용어는 여기서 멀티 캐스트 대리인을 지칭 할 수도 있습니다. 인터페이스에 의해 선언 된 메소드는 구현 클래스에서 한 번만 구현할 수 있습니다. 그러나 델리게이트는 여러 메소드를 누적 할 수 있으며이를 순차적으로 호출합니다.
따라서,이 안내서는 충분히 유익하지 않은 것으로 보이며 단지 규칙서가 아닌 안내서로서의 역할을합니다. 일부 조언은 실제로 약간 모순적으로 들릴 수 있습니다. 언제 무엇을 적용해야하는지 결정하는 것은 귀하의 책임입니다. 가이드는 우리에게 일반적인 길을주는 것 같습니다.
귀하의 질문이 귀하의 만족에 응답되기를 바랍니다. 그리고 다시, 질문에 대한 찬사.