2008-09-03 6 views
57

나는이 용어를 듣고 읽었지만 그 의미를 이해하지 못했다.C#에서 이중 디스패치?

언제이 기술을 사용해야하며 어떻게 사용합니까? 누구든지 좋은 코드 샘플을 제공 할 수 있습니까?

+0

현재이 방법을 사용하는 것이 가장 좋습니다. https://blogs.msdn.microsoft.com/curth/2008/11/15/c-dynamic-and-multiple-dispatch/ –

+0

두 배 급파 사례 [서식있는 도메인 모델을 만들기위한 오브젝트 구성 적용] (https://vimeo.com/195774910). – jsuddsjr

+0

[이중 발송주의] (https://lostechies.com/derekgreer/2010/04/19/double-dispatch-is-a-code-smell/). 아마 당신은 더 나은 코드 관리를 위해 그것을 피할 수 있습니다. –

답변

54

방문자 패턴은 객체 지향 방식으로 이중 디스패치를 ​​수행하는 방법입니다.

주어진 인수에 대해 컴파일 타임보다는 런타임에 유형을 기반으로 사용할 메소드를 선택하려는 경우 유용합니다.

이중 배송은 다중 배송의 특별한 경우입니다.

개체에서 가상 메서드를 호출하면 실제 메서드가 호출되는 단일 개체 유형에 따라 단일 디스패치로 간주됩니다.

이중 디스패치의 경우 개체의 형식과 메서드 단독 인수의 형식이 모두 고려됩니다. 이는 메소드 오버로드 해결과 비슷합니다. 단, 인수 유형은 컴파일 타임에 정적으로가 아니라 런타임시 double-dispatch로 결정됩니다.

다중 디스패치에서는 메서드에 여러 인수가 전달 될 수 있으며 사용되는 구현은 각 인수의 형식에 따라 다릅니다. 형식이 평가되는 순서는 언어에 따라 다릅니다. LISP에서는 처음부터 끝까지 각 유형을 확인합니다.

다중 발송을 사용하는 언어는 일반 기능을 사용합니다.이 기능은 단순한 기능 취소이며 유형 매개 변수를 사용하는 일반적인 방법과 다릅니다.

하는 C#을에 두 번 파견을 위해, 당신은 유일한 오브젝트 인수하는 방법을 선언 할 수 있습니다 특정 유형의 다음 구체적인 방법 :

using System.Linq; 

class DoubleDispatch 
{ 
    public T Foo<T>(object arg) 
    { 
     var method = from m in GetType().GetMethods() 
        where m.Name == "Foo" 
         && m.GetParameters().Length==1 
         && arg.GetType().IsAssignableFrom 
              (m.GetParameters()[0].GetType()) 
         && m.ReturnType == typeof(T) 
        select m; 

     return (T) method.Single().Invoke(this,new object[]{arg});   
    } 

    public int Foo(int arg) { /* ... */ } 

    static void Test() 
    { 
     object x = 5; 
     Foo<int>(x); //should call Foo(int) via Foo<T>(object). 
    } 
}  
+2

리플렉션을 사용한 LINQ의 멋진 사용 - 전에는 지루한 xxxInfo 개체에 적용 할 생각이 없었습니다. 감사! –

+24

나는 이것이 좋은 아이디어라고 확신하지 못한다. 이것은 실제로 double 디스패치를 ​​구현하지 않습니다. * type 매개 변수를 지정하기 위해 * 컴파일 할 때 * 유형을 알아야합니다! 모든 리플렉션 코드에 신경 쓰지 않고 단순히 오브젝트를 캐스팅 할 수도 있습니다. 내가 놓친 게 있니? – ljs

+4

DoubleDispatch에서 파생 된 런타임 형식의 개체와 메서드 인수 모두에서 디스패치한다는 점에서 이중 디스패치를 ​​구현합니다. 리턴 타입에 대한 반영은 마카니즘을 하위 클래스로 확장하는 데 사용되므로 "string Foo (string)"을 하위 클래스에 추가하면 작동합니다. –

11

얘들 아 글쎄, 마크가 게시 된 코드는 완전한 밤은 그리고 그곳에는 일이 없습니다.

그래서 조정 및 완료되었습니다.

class DoubleDispatch 
{ 
    public T Foo<T>(object arg) 
    { 
     var method = from m in GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) 
        where m.Name == "Foo" 
          && m.GetParameters().Length == 1 
          //&& arg.GetType().IsAssignableFrom 
          //     (m.GetParameters()[0].GetType()) 
          &&Type.GetType(m.GetParameters()[0].ParameterType.FullName).IsAssignableFrom(arg.GetType()) 
          && m.ReturnType == typeof(T) 
        select m; 


     return (T)method.Single().Invoke(this, new object[] { arg }); 
    } 

    public int Foo(int arg) 
    { 
     return 10; 
    } 

    public string Foo(string arg) 
    { 
     return 5.ToString(); 
    } 

    public static void Main(string[] args) 
    { 
     object x = 5; 
     DoubleDispatch dispatch = new DoubleDispatch(); 

     Console.WriteLine(dispatch.Foo<int>(x)); 


     Console.WriteLine(dispatch.Foo<string>(x.ToString())); 

     Console.ReadLine(); 
    } 
} 

감사합니다 마크와 더블 디스패처 패턴에 좋은 설명은 다른 사람

+0

동의합니다. 이 코드는 완전하며 실제로 이중 디스패치를 ​​보여줍니다. 마크의 대답과이 코드의 설명은 완벽하게 함께 전달됩니다. –

+0

쓰지 않겠습니까? "Console.WriteLine (dispatch.Foo (x));" 패턴을 활용하는 데보다 역동적이고 유용한 방법이 있습니까? –

0

C# 4는 (대신에 컴파일 시간) 런타임에 함수 호출을 해결 의사 유형 dynamic을 소개합니다. 즉, 표현식의 런타임 유형이 사용됩니다. 이중 (또는 다중 발송)은 다음으로 단순화 할 수 있습니다.

class C { } 

static void Foo(C x) => Console.WriteLine(nameof(Foo)); 
static void Foo(object x) => Console.WriteLine(nameof(Object)); 

public static void Main(string[] args) 
{ 
    object x = new C(); 

    Foo((dynamic)x); // prints: "Foo" 
    Foo(x);   // prints: "Object" 
} 

정수형을 사용할 경우주의하십시오. dynamicSystem.Object으로 처리되므로 위의 예에서는 절대로 void Foo(int x)을 호출하지 않습니다.

또한 dynamic을 사용하면 컴파일러가 정적 분석기로 코드의이 부분을 검사하지 못하게 할 수 있습니다. 신중하게 사용을 고려해야한다 dynamic.