2009-11-05 5 views
9

대리자 인스턴스가 함수 인스턴스와 상호 교환 가능하다고 생각했습니다. 당신은 C#을 사용하는 경우 당신은 적어도 내가 최대하지 않은 (차이를 볼 수 없을거야, 동등한 것으로 나타 호출대리자 인스턴스와 메서드 포인터의 차이점은 무엇입니까?

delegate int AddDelegate(int a, int b); 

AddDelegate DelegateInstance; 

public void DoStuff() 
{ 
    //I can call this without a delegate "instance": 
    MethodThatTakesAdd(Add); 

    //I can also call it WITH a delegate "instance" 
    DelegateInstance = Add; 
    MethodThatTakesAdd(DelegateInstance); 
} 

public int Add(int a, int b) 
{ 
    return a + b; 
} 

public void MethodThatTakesAdd(AddDelegate addFunction) 
{ 
    Console.WriteLine(addFunction(1, 2).ToString()); 
} 

두 가지 방법과 :

다음 코드를 가지고 이 점). 그러나 최근에이 관리 코드를 다시 호출하는 관리되지 않는 코드 였지만 다르게 처리되었습니다. 예를 들어, 한 시나리오에서 콜백으로 함수를 직접 사용하면 "가비지 수집 된 대리자에서 콜백이 발생했습니다."라는 오류 메시지가 나타납니다 (내 개체 인스턴스가 보관되어 있어도). "위임 인스턴스"를 사용하면 문제가 해결됩니다.

차이점을 알고있는 사람이 있습니까?

+1

il은 어떤 모습입니까? 후드 아래에 일반적으로 다르게 취급된다는 표시가 있습니까? –

답변

13

용어 해독 : 메소드 포인터 대신에 더 적절한 용어는 메소드 그룹입니다.

기능면에서 두 문장은 동일합니다. 그것은 그들이 거의 같은을 생산한다는 것입니다. 차이점은 위임 값이 저장되는 위치입니다.

첫 번째 경우 메서드 그룹에 전달하면 MethodThatTakesAdd에 직접 추가됩니다. 이로 인해 임시 대리자 값이 만들어지고 MethodThatTakesAdd에 전달됩니다. 이 대리자 값은 값을 저장하지 않았으므로 MethodThatTakesAdd가 반환하는 순간 가비지 수집 대상이됩니다.

두 번째 경우에는 외부 인스턴스의 필드에 대리인을 할당했습니다. 이것은 일 것입니다. 일반적으로은 델리게이트의 수명을 늘려서 pinvoke 호출 중에 가비지 수집 가능성을 줄입니다.

+0

그럴듯하게 들리 겠지만, 내가보고있는 것을 설명 할 것입니다! –

+0

http://msdn.microsoft.com/en-us/magazine/cc164193.aspx에서 "Reverse P/Invoke and Delegate Lifetime"절에서 설명합니다. –

+0

@JaredPar 이해가 안됩니다.이 'AddDelegate DelegateInstance;'는 델리게이트 ** 인스턴스 **입니까? 그것은 단지'AddDelegate' 타입의 변수입니다. 대리자 ** 인스턴스 **가'myDel + = new MYDEL (myMethod); - 또는'myDel + = myMethod;'(**)의 오른쪽면 ** 일 것입니다. .내가 잘못 ? –

0

대리자는 C 또는 C++에서 함수 포인터로 C#에서 동의어 기능을 제공하지만 중요한 차이점이 있습니다. 이 중 핵심은 대리자가 포인터가 아닌 클래스라는 것입니다.

즉, 포인터에 대리자를 캐스팅하면 함수 또는 메서드에 대한 참조가 제공되지 않으므로 비 관리 코드에서 참조로 메서드를 호출하는 데 사용할 수 없습니다.

4

대리인은 호출 할 수있는 클래스이며 포인터를 기능화하기 위해과 비슷한 동작을가집니다. 델리게이트는 내부적으로 호출 할 함수의 어드레스 (즉, 함수 포인터)를 저장하지만, 멀티 캐스팅 및 호출리스트 저장과 같은 다른 기능을 제공한다. 기본적으로 다음과 같이 하나의 위임 인스턴스로 동일한 서명의 많은 함수를 호출 할 수 있습니다. 당신이 MSIL 보면 C# 컴파일러가 라인 MethodThatTakesAdd(Add)을 위해 생성하는 MethodThatTakesAdd(Add)MethodThatTakesAdd(DelegateInstance), 의 동등성에 대한 메모와 관련

public void DoStuff() 
{ 
    DelegateInstance += Add; 
    DelegateInstance += AnotherAdd; 
    DelegateInstance += YetAnotherAdd; 

    // Invoke Add(100, 200), AnotherAdd(100, 200), and YetAnotherAdd(100, 200) 
    DelegateInstance(100, 200); 
} 

, 당신은 컴파일러가 대리자를 생성하고 Add() 방법을 포장되는 것을 알 수 있습니다 너를 위해서.

관련 문제