상세 c\#의뢰 체인

머리말:
이전 주제다음 컴 파일 러 가 어떻게 번역 의뢰 를 하 는 지 소 개 했 습 니 다.중간 언어의 측면 에서 의뢰 를 보면 여러분 들 이 의뢰 를 더욱 이해 하 는 데 도움 을 줄 수 있 기 를 바 랍 니 다.그러나 예전 의 소 개 는 모두 의뢰 가 하나의 방법 일 뿐 입 니 다.그 의뢰 는 여러 가지 방법 을 포장 할 수 있 습 니까?생활 속 에서 자주 듣 기 때문에 제 가 여러분 의 의견 을 대표 하 는 등 이런 말 을 합 니 다.의뢰 도 대표 이기 때문에 그 가 한 사람 만 대표 할 수 있다 면 그의 매력 은 그리 크 지 않 을 것 입 니 다.그래서 우 리 는 여러 가지 방법 을 대표 할 수 있 는 지 를 의뢰 할 것 입 니 다.답 은 가능 합 니 다.이것 이 바로 본 주제 에서 말 하고 자 하 는 내용 입 니 다.의뢰 체인 도 하나의 의뢰 입 니 다.단지 여러 개의 의뢰 체인 을 함께 연결 하기 때문에 우 리 는 의뢰 체인 으로 그것 을 부 릅 니 다.
1.의뢰 체인 이란 무엇 인가
우 리 는 평소에 의뢰 대상 을 예화 할 때 한 가지 방법 을 연결 시 켰 다.앞의 주제 에 소 개 된 의뢰 도 하나의 방법 을 포장 했다.앞의 예 를 들 어 변호 사 를 위임 한 사람 은 한 사람 밖 에 없다.즉,당사자 가 한 사람 밖 에 없다 는 것 이다.그러나 현실 생활 에서 분명히 그렇지 않다.소송 을 할 때 변호 사 는 여러 가지 사건 을 동시에 맡 을 수 있다.또한 여러 명의 당시 사람들의 위임 을 받 아 이 변호 사 는 여러 당사자 와 연결 되 어 여러 당사자 의 사건 상황 을 알 아야 한다.사실은 이것 이 바로 생활 속 의 위탁 체인 이다.이때 이 변호 사 는 한 사람의 대표 변호사 가 아니 라 여러 명의 당사자 의 변호사 이다.생활 속 의 위탁 체인 은 C\#중의 위탁 체인 과 매우 유사 하 다.지금 C\#중의 위탁 체인 이 도대체 무엇 인지 말 해 보 자.
우선 의뢰 체인 은 하나의 의뢰 이기 때문에 의뢰 체인 의 느낌 이 어떤 C\#의 새로운 특성 인지 보지 마 세 요.그러나 여러 개의 의뢰 체인 을 한데 묶 으 려 면 여러 개의 의뢰 의 인용 을 저장 해 야 합 니 다.그러면 의뢰 체인 대상 은 어디에서 여러 개의 의뢰 의 인용 을 저장 합 니까?우리 가 지난 주제 에서 우리 가 소개 한 의뢰 유형 은 세 개의 비공 식 필드 가 있 는 것 을 기억 하 십 니까?이 세 필드 는― 이다.target,methodPtr 와invocationList,이 세 필드 가 무엇 을 대표 하 는 지 에 대해 서 는 제 지난 주제 의 글 을 볼 수 있 습 니 다.그러나invocationList 필드 는 여러 의뢰 인용 을 저장 하 는 곳 입 니 다.
더 잘 설명 하기 위해invocationList 는 의뢰 인용 을 어떻게 저장 하 는 지 다음 에 의뢰 체인 의 예 와 운영 결 과 를 본 다음 에 원인 을 분석 합 니 다.

using System;

namespace DelegateTest

{
 public class Program
 {
  //         ,          
  //        int   ,  void  
  public delegate void DelegateTest(int parm);

  public static void Main(string[] args)
  {
   //            
   DelegateTest dtstatic = new DelegateTest(Program.method1);

   //            
   DelegateTest dtinstance = new DelegateTest(new Program().method2);
   
   //       
   dtstatic(1);

   //     Invoke       
   dtinstance.Invoke(1);

   //       
   dtstatic(2);

   //     Invoke       
   dtinstance.Invoke(2);
   Console.Read();
  }
  private static void method1(int parm)
  {
   Console.WriteLine("        ,    :" + parm);
  }

  private void method2(int parm)
  {
   Console.WriteLine("        ,    :" + parm);
  }
 }

}
실행 결과:

왜 이런 결과 가 나 왔 는 지 분석 해 보 겠 습 니 다.
처음에 우 리 는 두 개의 위탁 변 수 를 실례 화 했 는데 다음 과 같은 코드 가 있다.

 //            
   DelegateTest dtstatic = new DelegateTest(Program.method1);

   //            
   DelegateTest dtinstance = new DelegateTest(new Program().method2);
의뢰 변수 dtstatic 과 dtinstance 가 인용 한 의뢰 대상 의 초기 상 태 는 다음 과 같 습 니 다.

그 다음 에 저 희 는 의뢰 형식의 인용 변 수 를 정 의 했 습 니 다.delegatechain 은 처음에 의뢰 대상 이 없 었 고 빈 인용 이 었 습 니 다.아래 코드 를 실행 할 때...
delegatechain = (DelegateTest)Delegate.Combine(delegatechain, dtstatic);
Combine 방법 은 null 과 dtstatic 를 합병 하려 는 것 을 발 견 했 습 니 다.내부 에서 Combine 은 dtstatic 의 대상 으로 직접 돌아 갑 니 다.이때 delegatechain 과 dtstatic 변 수 는 모두 같은 의뢰 대상 을 참조 합 니 다.다음 그림 과 같 습 니 다.

이때 Combine 방법 은 delegatechain 이 의뢰 대상 을 인용 한 것 을 발견 했다.target 과methodPtr 필드 를 초기 화한 다음invocationList 필드 는 의뢰 대상 을 인용 한 배열 로 초기 화 되 었 습 니 다.이 배열 의 첫 번 째 요 소 는 method 1 방법 을 인용 한 의뢰 로 초기 화 되 었 습 니 다.배열 의 두 요 소 는 method 2 방법 을 인용 한 의뢰(즉 dtinstance 참조 의뢰 대상)로 초기 화 되 었 습 니 다.마지막 으로 delegaechain 은 새로 만 든 이 의뢰 대상 을 참조 하 는 것 으로 설정 되 었 습 니 다.다음은 그림 입 니 다.의뢰 체인 을 이해 하 는 데 도움 을 줄 수 있 습 니 다(멀티캐스트 의뢰 라 고도 합 니 다).

마찬가지 로 세 번 째 의뢰 체인 을 추가 하면 과정 도 위 와 같 습 니 다.이때 의뢰 대상 을 새로 만 듭 니 다.이때invocationList 필드 는 이 세 개의 의뢰 대상 배열 을 저장 하 는 것 을 참조 하 는 것 으로 초기 화 됩 니 다.그러나 누 군 가 는 의뢰 대상 의 의뢰 유형 변 수 를 Combine 방법 으로 호출 한 후 새로운 의뢰 대상 을 만 들 고 새로운 의뢰 대상 의 세 필드 를 다시 초기 화 합 니 다.마지막 으로 이전 의뢰 유형 변 수 를 새로 만 든 의뢰 대상(여기 서 의뢰 체인 의 생 성 과정 을 정리 해 드 립 니 다)을 참조 하면 이전 의뢰 대상 은 어떻게 합 니까?대부분의 사람들 이 이 의문 을 가지 고 있 을 것 이 라 고 믿 습 니 다.이 점 은 문자열 의 Concat 방법 과 비슷 합 니 다.이전 의뢰 대상 과--invocationList 필드 에서 인용 한 배열 은 쓰레기 로 회수 되 기 때 문 입 니 다.(그 렇 기 때문에 의뢰 는 문자열 String 과 마찬가지 로 변 하지 않 습 니 다.)
메모:다음 코드 를 호출 할 때 Delegate 의 Remove 방법 을 사용 하여 체인 에서 의뢰 를 삭제 할 수 있 습 니 다.
delegatechain =(DelegateTest)Delegate.Remove(delegatechain,new DelegateTest(method1));
Remove 방법 이 호출 될 때 delegateChain(첫 번 째 매개 변수)이 인용 한 의뢰 대상 내부 유 지 를 위 한 의뢰 배열 을 스 캔 합 니 다.delegateChain 이 인용 한 의뢰 대상 을 찾 으 면target 과methodPtr 필드
두 번 째 인자(새로 만 든 의뢰)의 필드 와 일치 하 는 의뢰 입 니 다.삭제 후 배열 에 하나의 데이터 항목 만 남 았 을 때 그 데이터 항목 을 되 돌려 줍 니 다.(의뢰 대상 을 새로 만 들 지 않 고 초기 화 합 니 다.이때 의invocationList 는 null 입 니 다.의뢰 대상 이 인용 한 배열 을 저장 하 는 것 이 아 닙 니 다.구체 적 으로 Remove 한 후 디 버 깅 할 수 있 습 니 다)이 때 배열 에 여러 개의 데이터 항목 이 남아 있다 면 의뢰 대상 을 새로 만 들 고 초기 화 합 니 다.invocationList 배열(이 때 배열 이 인용 한 의뢰 대상 이 하나 줄 었 습 니 다.Remove 방법 으로 삭 제 했 기 때 문 입 니 다).또한,매번 Remove 방법 이 호출 될 때마다 체인 에서 하나의 의뢰 만 삭제 할 수 있 고 일치 하 는 을 삭제 하지 않 습 니 다.target 과methodPtr 필드 의 모든 의뢰(이것 은 디 버 깅 할 수 있 습 니 다)
2.어떻게 의뢰 체인 중의 위탁 호출 을 통제 합 니까?
위 를 통 해 여러분 은 의뢰 체인 대상 을 어떻게 만 드 는 지 이해 할 수 있 을 것 이 라 고 믿 습 니 다.그러나 운영 결과 에서 알 수 있 듯 이 의뢰 체인 을 호출 할 때마다 의뢰 체인 포장 의 모든 방법 이 순서대로 실 행 됩 니 다.만약 에 의뢰 체인 에서 호출 된 의뢰 가 이상 을 던 지면 체인 중의 후속 모든 대상 이 호출 되 지 못 합 니 다.또한 의뢰 의 앞 에 void 가 아 닌 반환 형식 이 있다 면 마지막 반환 값 만 보류 되 고 다른 모든 반환 방법의 반환 값 은 버 려 집 니 다.이것 은 다른 모든 작업 의 반환 값 이 영원히 볼 수 없다 는 것 을 의미 합 니까?사실은 그렇지 않 습 니 다.저 희 는 Delegate.GetInvocationList 방법 으로 체인 의 모든 의뢰 를 표시 하고 자신의 정의 출력 을 추가 할 수 있 습 니 다.
GetInvocation List 방법 은 Delegate 참조 로 구 성 된 배열 을 되 돌려 줍 니 다.그 중에서 모든 배열 은 체인 의 의뢰 대상 을 가리 키 고 있 습 니 다.내부 에서 GetInvocationList 는 하나의 배열 을 만 들 고 초기 화 시 켜 데이터 의 모든 요소 가 체인 의 의뢰 를 참조 한 다음 이 배열 에 대한 인용 을 되 돌려 줍 니 다.하면,만약,만약...invocationList 필드 는 null 입 니 다.돌아 오 는 배열 은 하나의 요소 만 있 습 니 다.이 요 소 는 인 스 턴 스 자체 에 의뢰 하 는 것 입 니 다.다음은 프로그램 을 통 해 보 여 드 리 겠 습 니 다.

namespace DelegateChainDemo
{
 class Program
 {
  //         ,          
  //        int   ,  void  
  public delegate string DelegateTest();

  static void Main(string[] args)
  {
   //            
   DelegateTest dtstatic = new DelegateTest(Program.method1);

   //            
   DelegateTest dtinstance = new DelegateTest(new Program().method2);
   DelegateTest dtinstance2 = new DelegateTest(new Program().method3);
   //          ,       null,         (    ,       )
   DelegateTest delegatechain = null;
   delegatechain += dtstatic;
   delegatechain += dtinstance;
   delegatechain += dtinstance2;

   ////delegatechain =(DelegateTest)Delegate.Remove(delegatechain,new DelegateTest(method1));
   ////delegatechain = (DelegateTest)Delegate.Remove(delegatechain, new DelegateTest(new Program().method2));
   Console.WriteLine(Test(delegatechain));
   Console.Read();
  }

  private static string method1()
  {
   return "      1";
  }

  private string method2()
  {
   throw new Exception("       ");
  }

  private string method3()
  {
   return "      3";
  }
  //          
  private static string Test(DelegateTest chain)
  {
   if (chain == null)
   {
    return null;
   }

   //               
   StringBuilder returnstring = new StringBuilder();

   //         ,              
   Delegate[] delegatearray=chain.GetInvocationList();

   //           
   foreach (DelegateTest t in delegatearray)
   {
    try
    {
     //         
     returnstring.Append(t() + Environment.NewLine);
    }
    catch (Exception e)
    {
     returnstring.AppendFormat("    {0}      ,      :{1}{2}", t.Method.Name, e.Message, Environment.NewLine);
    }
   }

   //          
   return returnstring.ToString();
  }
 }
}
실행 결과 캡 처:

정리 하 다
본 주 제 는 의뢰 체인 을 만 드 는 방법 과 의뢰 체인 을 만 드 는 과정 에 대해 상세 하 게 공 유 했 습 니 다.두 번 째 부분 은 의뢰 의 한계점 을 지적 한 다음 에 GetInvocationList 방법 을 호출 하여 의뢰 배열 로 돌아 갑 니 다.그러면 의뢰 배열 의 모든 의뢰 를 옮 겨 다 니 며 의뢰 의 호출 과정 을 알 릴 수 있 습 니 다.이렇게 하면 위탁 체인 의 호출 에 대해 더 많은 통 제 를 할 수 있다.이 세 가지 주 제 를 통 해 의뢰 에 대한 소 개 를 통 해 여러분 들 이 의뢰 에 대해 더욱 깊이 이해 할 것 이 라 고 믿 습 니 다.그리고 왜 세 가지 주 제 를 써 서 의뢰 를 상세 하 게 소개 해 야 합 니까?주로 다음 에 소개 할 사건 입 니 다.Lambda 표현 식,Linq 의 내용 은 모두 의뢰 와 관련 이 있 기 때문에 의뢰 를 잘 이해 하 는 것 이 뒤의 특성의 기초 가 될 것 입 니 다.이런 것들 이 여러분 에 게 도움 이 되 기 를 바 랍 니 다.저 는 다음 주제 에서 사건 을 소개 하 겠 습 니 다.
이상 은 c\#의뢰 체인 에 대한 상세 한 내용 입 니 다.c\#의뢰 체인 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기