델리게이트 vs 인터페이스-더 많은 설명이 있습니까?


23

인터페이스 대신 델리게이트를 사용하는시기 (C # 프로그래밍 가이드) 기사를 읽은 후 아래의 주어진 사항을 이해하는 데 도움이 필요합니다. 이에 대한 예나 자세한 설명이 있습니까?

다음과 같은 경우 대리인을 사용하십시오.

  • 이벤트 디자인 패턴이 사용됩니다.
  • 정적 메소드를 캡슐화하는 것이 바람직합니다.
  • 쉬운 구성이 바람직하다.
  • 클래스는 하나 이상의 메소드 구현이 필요할 수 있습니다.

다음과 같은 경우 인터페이스를 사용하십시오.

  • 호출 될 수있는 관련 메소드 그룹이 있습니다.
  • 클래스는 하나의 메소드 구현 만 필요합니다.

내 질문은

  1. 이벤트 디자인 패턴의 의미는 무엇입니까?
  2. 델리게이트를 사용하면 컴포지션이 어떻게 쉬운 지 알 수 있습니까?
  3. 호출 될 수있는 관련 메소드 그룹이있는 경우 인터페이스를 사용하십시오. 어떤 이점이 있습니까?
  4. 클래스에 메소드의 구현이 하나만 필요한 경우 인터페이스를 사용하십시오. 이점 측면에서 어떻게 정당화됩니까?

답변:


11

이벤트 디자인 패턴의 의미는 무엇입니까?

이들은 C #의 핵심 언어 구조 인 옵저버 패턴 의 구현을 ' 이벤트 ' 로 노출 했을 가능성이 높습니다 . 이벤트를 듣는 것은 델리게이트를 연결함으로써 가능합니다. Yam Marcovic이 지적했듯이 EventHandler이벤트의 일반적인 기본 대리자 유형이지만 모든 대리자 유형을 사용할 수 있습니다.

델리게이트를 사용하면 컴포지션이 어떻게 쉬운 지 알 수 있습니까?

이것은 아마도 대리인이 제공하는 유연성을 나타냅니다. 특정 행동을 쉽게 '구성'할 수 있습니다. lambdas 의 도움으로 이를 수행하는 구문도 매우 간결합니다. 다음 예를 고려하십시오.

class Bunny
{
    Func<bool> _canHop;

    public Bunny( Func<bool> canHop )
    {
        _canHop = canHop;
    }

    public void Hop()
    {
        if ( _canHop() )  Console.WriteLine( "Hop!" );
    }
}

Bunny captiveBunny = new Bunny( () => IsBunnyReleased );
Bunny lazyBunny = new Bunny( () => !IsLazyDay );
Bunny captiveLazyBunny = new Bunny( () => IsBunnyReleased && !IsLazyDay );

인터페이스와 비슷한 작업을 수행하려면 전략 패턴을 사용하거나 Bunny보다 구체적인 토끼를 확장 하는 (추상적 인) 기본 클래스를 사용해야합니다.

호출 될 수있는 관련 메소드 그룹이있는 경우 인터페이스를 사용하십시오. 어떤 이점이 있습니까?

다시 한 번 토끼를 사용하여 더 쉬운 방법을 보여 드리겠습니다.

interface IAnimal
{
    void Jump();
    void Eat();
    void Poo();
}

class Bunny : IAnimal { ... }
class Chick : IAnimal { ... }

// Using the interface.
IAnimal bunny = new Bunny();
bunny.Jump();  bunny.Eat();  bunny.Poo();
IAnimal chick = new Chick();
chick.Jump();  chick.Eat();  chick.Poo();

// Without the interface.
Action bunnyJump = () => bunny.Jump();
Action bunnyEat = () => bunny.Eat();
Action bunnyPoo = () => bunny.Poo();
bunnyJump(); bunnyEat(); bunnyPoo();
Action chickJump = () => chick.Jump();
Action chickEat = () => chick.Eat();
...

클래스에 메소드의 구현이 하나만 필요한 경우 인터페이스를 사용하십시오. 이점 측면에서 어떻게 정당화됩니까?

이를 위해 토끼가있는 첫 번째 예를 다시 고려하십시오. 사용자 정의 구성이 필요하지 않은 구현이 하나만 필요한 경우이 동작을 인터페이스로 노출 할 수 있습니다. 람다를 만들 필요가 없으며 인터페이스를 사용할 수 있습니다.

결론

대의원은 훨씬 더 많은 유연성을 제공하는 반면 인터페이스는 강력한 계약을 설정하는 데 도움이됩니다. 따라서 마지막으로 언급 한 "클래스에는 메소드 구현이 두 개 이상 필요할 수 있습니다." 가장 관련성이 높은 것입니다.

델리게이트를 사용해야하는 또 다른 이유는 소스 파일을 조정할 수없는 클래스의 일부만 노출하려는 경우입니다.

이러한 시나리오 (최대 유연성, 소스를 수정할 필요 없음)의 예로, 두 대의자를 전달하여 가능한 모든 콜렉션에 대해 이진 검색 알고리즘구현하는 것을 고려 하십시오 .


12

델리게이트는 단일 메소드 서명을위한 인터페이스와 유사하며 일반 인터페이스처럼 명시 적으로 구현할 필요가 없습니다. 실행시 구성 할 수 있습니다.

인터페이스는 계약을 나타내는 언어 구조 일뿐입니다. "이에 따라 다음과 같은 방법과 속성을 사용할 수 있습니다."

또한 대리자가 관찰자 / 구독자 패턴에 대한 솔루션으로 사용될 때 주로 유용하다는 데 완전히 동의하지는 않습니다. 그러나 "자바 상세도"에 대한 훌륭한 해결책입니다.

질문이 있으시면 :

1 & 2)

Java로 이벤트 시스템을 작성하려면 일반적으로 인터페이스를 사용하여 이벤트를 전파하십시오.

interface KeyboardListener
{
    void KeyDown(int key);
    void KeyUp(int key)
    void KeyPress(int key);
    .... and so on
}

즉, 클래스는 이러한 모든 메소드를 명시 적으로 구현해야하며 단순히 구현하려는 경우에도 모든 메소드에 대한 스텁을 제공해야합니다 KeyPress(int key).

C #에서 이러한 이벤트는 각 단일 이벤트에 대해 하나씩 c #의 "event"키워드에 의해 숨겨진 위임 목록으로 표시됩니다. 즉, 공개 "Key"메소드 등으로 수업에 부담을주지 않고 원하는 것을 쉽게 구독 할 수 있습니다.

포인트 3-5의 경우 +1

또한 :

대표자는 예를 들어 "지도"기능을 제공 할 때 매우 유용합니다.이 기능은 목록을 가져와 각 요소를 같은 양의 요소를 사용하지만 새로운 방식으로 새 목록으로 투영합니다. 기본적으로 IEnumerable.Select (...).

IEnumerable.Select는 Func<TSource, TDest>TSource 요소를 가져 와서 해당 요소를 TDest 요소로 변환하는 함수를 래핑하는 델리게이트 인을 사용합니다.

Java에서는 인터페이스를 사용하여 구현해야합니다. 그러한 인터페이스를 구현할 자연적인 장소가없는 경우가 종종 있습니다. 어떤 방식으로 변환하고자하는리스트가 클래스에 포함되어 있다면, "ListTransformer"인터페이스를 구현하는 것은 그리 자연스럽지 않습니다. 특히 다른 방식으로 변환되어야하는 두 개의 다른리스트가있을 수 있기 때문입니다.

물론, 비슷한 개념 인 자바에서 익명 클래스를 사용할 수 있습니다.


실제로 질문에 답하기 위해 게시물을 편집 해보십시오
Yam Marcovic

@YamMarcovic 네 말이 맞아, 나는 그의 질문에 직접 대답하는 대신 자유형으로 조금 엉망이었다. 아직도, 나는 그것이 관련된 역학에 대해 조금 설명한다고 생각합니다. 또한 그의 질문은 내가 그 질문에 대답했을 때 약간 덜 구성되었습니다. : p
Max

당연히. 나에게도 일어 났으며 그 자체의 가치가 있습니다. 그래서 나는 단지 그것을 제안 했지만 그것에 대해 불평하지 않았습니다. :)
Yam Marcovic

3

1) 이벤트 패턴, 클래식은 Observer 패턴입니다. 여기에 Microsoft 링크가 있습니다. Microsoft talk Observer

연결 한 기사는 잘 작성되지 않았으며 필요한 것보다 복잡하게 만듭니다. 정적 비즈니스는 상식이므로 정적 멤버로 인터페이스를 정의 할 수 없으므로 정적 메소드에서 다형성 동작을 원할 경우 대리자를 사용합니다.

위의 링크는 델리게이트와 컴포지션이 좋은 이유에 대해 설명하므로 쿼리에 도움이 될 수 있습니다.


3

우선, 좋은 질문입니다. 나는 맹목적으로 "모범 사례"를 받아들이지 않고 유틸리티에 초점을두고 있습니다. +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 대체 원칙을 위반합니다 . 정적 입력과 같습니다.

이 용어는 여기서 멀티 캐스트 대리인을 지칭 할 수도 있습니다. 인터페이스에 의해 선언 된 메소드는 구현 클래스에서 한 번만 구현할 수 있습니다. 그러나 델리게이트는 여러 메소드를 누적 할 수 있으며이를 순차적으로 호출합니다.

따라서,이 안내서는 충분히 유익하지 않은 것으로 보이며 단지 규칙서가 아닌 안내서로서의 역할을합니다. 일부 조언은 실제로 약간 모순적으로 들릴 수 있습니다. 언제 무엇을 적용해야하는지 결정하는 것은 귀하의 책임입니다. 가이드는 우리에게 일반적인 길을주는 것 같습니다.

귀하의 질문이 귀하의 만족에 응답되기를 바랍니다. 그리고 다시, 질문에 대한 찬사.


2

.NET의 메모리가 여전히 유지되면 대리자는 기본적으로 함수 ptr 또는 functor입니다. 호출 코드를 변경하지 않고도 함수를 대체 할 수 있도록 함수 호출에 간접 계층을 추가합니다. 인터페이스가 여러 기능을 함께 패키지하고 구현자가 함께 구현해야한다는 점을 제외하면 인터페이스와 동일한 기능입니다.

일반적으로 말하면 이벤트 패턴은 Windows 메시지와 같이 다른 곳의 이벤트에 응답하는 패턴입니다. 일련의 이벤트는 일반적으로 개방형이며 어떤 순서로든 올 수 있으며 반드시 서로 관련이있는 것은 아닙니다. 각 이벤트는 관련없는 여러 함수를 포함 할 수있는 일련의 구현 개체에 대한 참조가 없어도 각 이벤트가 단일 함수를 호출 할 수 있다는 점에서이 기능이 제대로 작동합니다. 또한 (여기서 .NET 메모리가 모호한 곳) 여러 대의원을 이벤트에 연결할 수 있다고 생각합니다.

합성이란 용어에 익숙하지 않지만 기본적으로 하나의 객체를 설계하여 여러 하위 파트 또는 작업이 전달되는 집계 된 하위를 갖습니다. 대표단은 인터페이스가 과도하게 사용되거나 너무 많은 커플 링과 함께 제공되는 강성과 취약성을 유발할 수있는보다 임시 방식으로 자녀를 혼합하고 일치시킬 수 있습니다.

관련 메소드에 대한 인터페이스의 이점은 메소드가 구현 오브젝트의 상태를 공유 할 수 있다는 것입니다. 델리게이트 함수는 상태를 완전히 공유하거나 포함 할 수 없습니다.

클래스에 단일 구현이 필요한 경우 전체 컬렉션을 구현하는 모든 클래스 내에서 하나의 구현 만 수행 할 수 있으므로 구현 클래스 (상태, 캡슐화 등)의 이점을 얻을 수 있으므로 인터페이스가 더 적합합니다. 런타임 상태로 인해 구현이 변경 될 수있는 경우 다른 메서드에 영향을주지 않고 다른 구현으로 교체 할 수 있기 때문에 대리자가 더 잘 작동합니다. 예를 들어, 각각 두 가지 가능한 구현이있는 세 개의 델리게이트가있는 경우 가능한 모든 상태 조합을 설명하기 위해 세 가지 방법 인터페이스를 구현하는 8 개의 다른 클래스가 필요합니다.


1

"이벤트"디자인 패턴 (관찰자 패턴이라고도 함)을 사용하면 동일한 서명의 여러 메서드를 대리인에게 연결할 수 있습니다. 실제로 인터페이스로는 그렇게 할 수 없습니다.

나는 인터페이스보다 델리게이트가 구성이 더 쉽다는 것을 전혀 확신하지 못한다. 매우 이상한 말입니다. 익명의 메서드를 대리인에게 첨부 할 수 있기 때문에 그가 의미하는지 궁금합니다.


1

내가 제공 할 수있는 가장 큰 설명 :

  1. 델리게이트는 함수 시그니처를 정의합니다. 함수 시그니처는 일치하는 함수가 받아 들일 매개 변수와 반환 할 내용을 정의합니다.
  2. 인터페이스는 전체 기능, 이벤트, 속성 및 필드 집합을 처리합니다.

그래서:

  1. 동일한 서명으로 일부 함수를 일반화하려면 대리자를 사용하십시오.
  2. 클래스의 동작 또는 품질을 일반화하려면 인터페이스를 사용하십시오.

1

이벤트에 대한 귀하의 질문은 이미 잘 다루었습니다. 또한 인터페이스 여러 메소드를 정의 할 있지만 (실제로는 필요하지는 않지만) 함수 유형은 개별 함수에 제약 조건 만 적용합니다.

그러나 실제 차이점은 다음과 같습니다.

  • 함수 값은 구조적 서브 타이핑 (즉, 요구되는 구조와의 암시 적 호환성)에 의해 함수 유형과 일치합니다 . 즉, 함수 값에 함수 유형과 호환되는 서명이 있으면 해당 유형에 유효한 값입니다.
  • 인스턴스는 명목 서브 타이핑 (즉, 이름의 명시 적 사용)에 의해 인터페이스와 일치합니다 . 즉, 인스턴스가 클래스의 멤버이고 지정된 인터페이스를 명시 적으로 구현하는 경우 인스턴스는 인터페이스에 유효한 값입니다. 그러나 개체에 인터페이스에서 요구하는 모든 멤버 만 있고 모든 멤버가 호환되는 서명을 가지고 있지만 인터페이스를 명시 적으로 구현하지 않은 경우 인터페이스에 유효한 값이 아닙니다.

물론, 이것이 무엇을 의미합니까?

이 예제를 보자 (내 C #이 좋지 않기 때문에 코드가 haXe에 있음) :

class Collection<T> {
    /* a lot of code we don't care about now */
    public function filter(predicate:T->Bool):Collection<T> { 
         //build a new collection with all elements e, such that predicate(e) == true
    }
    public function remove(e:T):Bool {
         //removes an element from this collection, if contained and returns true, false otherwise
    }
}

이제 필터 방법을 사용하면 컬렉션의 내부 구성을 알지 못하는 작은 로직 만 편리하게 전달할 수 있으며 컬렉션은 주어진 로직에 의존하지 않습니다. 큰. 한 가지 문제를 제외하고 :
컬렉션 논리에 따라 다릅니다. 컬렉션은 본질적으로 전달 된 함수가 조건에 대해 값을 테스트하고 테스트의 성공을 반환하도록 설계되었다고 가정합니다. 하나의 값을 인수로 사용하고 부울을 리턴하는 모든 함수가 실제로 단순한 술어는 아닙니다. 예를 들어 컬렉션의 remove 메소드는 그러한 함수입니다.
전화했다고 가정 해 봅시다 c.filter(c.remove). 결과는 모든 요소가 포함 된 모음입니다.c while의c자체가 비게됩니다. 당연히 우리는 c변하지 않을 것으로 예상하기 때문에 불행한 일 입니다.

예제는 매우 구성되어 있습니다. 그러나 중요한 문제는 c.filter인수로 일부 함수 값을 호출하는 코드 가 해당 인수가 적합한 지 여부를 알 수 없다는 것입니다 (즉, 궁극적으로 불변을 보존합니다). 함수 값을 작성한 코드는 술어로 해석 될 수도 있고 알지 못할 수도 있습니다.

이제 변경해 봅시다 :

interface Predicate<T> {
    function test(value:T):Bool;
}
class Collection<T> {
    /* a lot of code we don't care about now */
    public function filter(predicate:Predicate<T>):Collection<T> { 
         //build a new collection with all elements e, such that predicate.test(e) == true
    }
    public function remove(e:T):Bool {
         //removes an element from this collection, if contained and returns true, false otherwise
    }
}

무엇이 바뀌 었습니까? 변한 것은 값이 지금에 주어진다 무엇 이건,이다 filter있다 명시 적 술어가되는 계약을 체결했다. 물론 악의적이거나 매우 어리석은 프로그래머는 부작용이없고 따라서 술어가 아닌 인터페이스의 구현을 만듭니다.
그러나 더 이상 일어날 수없는 것은 누군가 외부 데이터 구조 때문에 실수로 술어로 해석되는 논리적 데이터 / 코드 단위를 묶는 것입니다.

따라서 위에서 말한 내용을 몇 마디로 바꾸려면 :

  • 인터페이스 는 명목상의 타이핑을 사용함으로써 명시적인 관계를 의미합니다.
  • 델리게이트 는 구조적 타이핑을 사용하여 암시 적 관계를 의미합니다.

명시 적 관계의 장점은 확실 할 수 있다는 것입니다. 단점은 명시 성의 오버 헤드가 필요하다는 것입니다. 반대로, 암시 적 관계의 단점 (이 경우 원하는 서명과 일치하는 함수의 서명 하나)은 실제로 이런 방식으로 사용할 수 있다고 100 % 확신 할 수 없다는 것입니다. 장점은 모든 오버 헤드없이 관계를 설정할 수 있다는 것입니다. 구조가 허용하기 때문에 물건을 빨리 던질 수 있습니다. 그것이 쉬운 구성의 의미입니다.
레고와 비슷 합니다. 스타 워즈 레고 피겨를 레고 해적선에 간단히 꽂을 수 있습니다. 단순히 외부 구조가 허용하기 때문입니다. 이제는 그것이 몹시 잘못되었다고 느끼거나 정확히 원하는 것일 수 있습니다. 아무도 당신을 막을 수 없습니다.


1
"명시 적 서브 타이핑"하에서 "명시 적으로 인터페이스 구현"은 인터페이스 멤버의 명시 적 또는 암시 적 구현과 동일하지 않다는 점을 언급 할 가치가 있습니다. C #에서 클래스는 항상 말한 것처럼 구현하는 인터페이스를 명시 적으로 선언해야합니다. 그러나 인터페이스 멤버는 명시 적으로 (예를 들어 int IList.Count { get { ... } }) 또는 내재적으로 ( public int Count { get { ... } }) 로 구현 될 수 있습니다 . 이 차이점은이 토론과 관련이 없지만 혼란스러워하는 독자를 피할만한 언급이 필요합니다.
phoog

@phoog : 예, 수정 해 주셔서 감사합니다. 나는 첫번째 것이 가능하다는 것을 몰랐다. 그러나 언어가 실제로 인터페이스 구현을 시행하는 방법은 매우 다양합니다. 예를 들어 Objective-C에서는 구현되지 않은 경우에만 경고를 표시합니다.
back2dos

1
  1. 이벤트 디자인 패턴은 게시 및 구독 메커니즘이 포함 된 구조를 의미합니다. 이벤트는 소스에 의해 게시되며 모든 구독자는 게시 된 항목의 자체 복사본을 가져와 자체 작업을 담당합니다. 게시자가 구독자가 있는지 알 필요가 없기 때문에 느슨하게 결합 된 메커니즘입니다. 가입자를 갖는 것은 물론 필수는 아닙니다.
  2. 인터페이스와 비교하여 델리게이트가 사용되는 경우 컴포지션은 "더 쉬워" 인터페이스는 컴포지션 구성 인스턴스가 "핸들러를 가짐"으로 보이는 것처럼 "인스턴스 핸들러"개체로 클래스 인스턴스를 정의하므로 델리게이트를 사용하여 인스턴스의 모양이 덜 제한되고 더욱 유연 해집니다.
  3. 아래의 의견에서 게시물을 개선해야한다는 것을 알았습니다 .http : //bytes.com/topic/c-sharp/answers/252309-interface-vs-delegate

1
3. 델리게이트가 더 많은 캐스팅을 요구하는 이유는 무엇입니까? 4. 대리자를 사용하기 위해 이벤트를 사용할 필요가 없으며 대리자와 함께 메소드를 보유하는 것과 같습니다. 반환 유형과 인수 유형을 알고 있습니다. 또한 왜 인터페이스에 선언 된 메소드가 델리게이트에 첨부 된 메소드보다 오류를보다 쉽게 ​​처리 할 수 ​​있습니까?
얌 마르코비치

대의원의 사양에 한해서만 맞습니다. 그러나 이벤트 처리의 경우 (적어도 그것은 내 참조가 관련된 것입니다) 항상 사용자 정의 유형의 컨테이너 역할을하는 일종의 eventArgs를 상속해야하므로 값을 안전하게 테스트하는 대신 항상 값을 처리하기 전에 유형을 풀어야합니다.
Carlo Kuip

인터페이스에 정의 된 메소드가 오류를 쉽게 처리 할 수 ​​있다고 생각하는 이유는 컴파일러가 해당 메소드에서 throw 된 예외 유형을 확인할 수 있기 때문입니다. 나는 그것이 설득력있는 증거가 아니라는 것을 알고 있지만 아마도 선호로 언급되어야 하는가?
Carlo Kuip

1
먼저 이벤트 대 인터페이스가 아니라 대리자 대 인터페이스에 대해 이야기했습니다. 둘째, EventHandler 대리자를 기반으로 이벤트 자체를 만드는 것은 단지 관습이며 결코 필수는 아닙니다. 그러나 여기서도 사건에 대해 이야기하면 요점을 놓치게됩니다. 두 번째 의견은 C #에서 예외가 확인되지 않습니다. Java와 혼동되고 있습니다 (실수로 델리게이트조차 없습니다).
얌 마르코비치

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