C\#역 변 과 협 변 에 대한 상세 한 설명

이 글 은 delegate 와 Lambda 표현 식 을 많이 사 용 했 습 니 다.만약 당신 이 이런 것 에 익숙 하지 않다 면 제 글 인,을 보 세 요.완전한 지식 체 계 를 구축 하 는 데 도움 을 줄 수 있 습 니 다.
C\#탄생 부터 발전 까지 새로운 지식 이 끊임없이 도입 된다.역 변 과 협 변 은 C\#가 독창적 인 것 이 아니 라 후속 도입 에 속한다.자바 에 도 역 변 과 협 변 이 존재 합 니 다.그 다음 에 저 는 자바 역 변 협 변 의 글 을 쓸 것 입 니 다.관심 이 있 는 분 들 은 관심 을 가 져 보 세 요.
역 변 과 협 변 은 추상 적 이 고 심오 하 게 들 리 지만 사실은 매우 간단 하 다.다음 코드 보기:

class Person
 {

 }
 class Student : Person
 {

 }
 class Teacher: Person
 {

 }
 
 class Program
 {
  static void Main(string[] args)
  {
   List<Person> plist = new List<Person>();
   plist = new List<Student>();
   plist = new List<Teacher>();
}
}

위의 코드 에서 plist=new List(),plist=new List()두 문장 에 컴 파일 오류 가 발생 했 습 니 다.Person 은 Student/Teacher 의 부모 클래스 이지 만 List유형 은 List유형의 부모 클래스 가 아니 기 때문에 위의 할당 문 구 는 형식 전환 에 실 패 했 습 니 다.
위 와 같은 할당 작업 은 C\#4.0 이전에 허용 되 지 않 았 습 니 다.왜 허용 되 지 않 는 지 유형 안전 이 가장 중요 한 요소 입 니 다.다음 예제 코드 를 보십시오.

List<Person> plist = new List<Student>();
plist.Add(new Person());
plist.Add(new Student());
plist.Add(new Teacher());
다음 예제 에서 Listplist=new List()가 할당 을 허용 한다 고 가정 하면 plist 는 List집합 이지 만 실제 지향 은 List집합 입 니 다.plist.add(new Person()),실제 호출 작업 을 추가 한 것 은 List.add()입 니 다.Person 유형 은 Student 로 안전하게 전환 할 수 없 기 때문에 이러한 집합 정 의 는 의미 가 없 기 때문에 위의 가설 은 성립 되 지 않 습 니 다.
그러나 상황 은 C\#4.0 이후 변 했 고'있 을 수 없 는 일이 일 어 났 다'는 것 이 아니 라 응용의 유연성 에 새로운 조정 이 이 뤄 졌 다.같은 C\#4.0 에서 위의 프로그램 은 여전히 허용 되 지 않 지만 예외 가 생 겼 다.C\#4.0 부터 범 형 의뢰,범 형 인터페이스 에서 특수 상황 의 발생 을 허용 한다(실질 적 으로 특별한 변화 가 발생 하지 않 았 고 나중에 설명 한다).다음 예제:

delegate void Work<T>(T item);

class Person
{
  public string Name { get; set; }
}
class Student : Person
{
  public string Like { get; set; }
}
class Teacher : Person
{
  public string Teach { get; set; }
}

class Program
{
  static void Main(string[] args)
  {
   Work<Person> worker = (p) => { Console.WriteLine(p.Name); }; ;
   Work<Student> student_worker = (s) => { Console.WriteLine(s.Like); };
   student_worker = worker; //      
  }
}

앞의 이론 적 지지 에 따라 studentworker = worker;의 잘못 은 이해 하기 쉽다.하지만 여기 서 우리 프로그램의 목적 은 woker 를  Work기능 을 충당 하여 나중에 student 호출worker(s)가 실제 호출 한 것 은 woker(s)입 니 다.우리 의 수 요 를 만족 시 키 기 위해 서 는 절차 가 두 가지 측면 에서 처리 해 야 한다.
1、student 호출 중worker(s)는 실질 적 으로 woker(s)를 실행 하기 때문에 s 변수의 유형 이 woker 에 필요 한 매개 변수 형식 으로 성공 적 으로 전환 되 어야 합 니 다.
2.컴 파일 러 에 알려 야 합 니 다.여기 서 Work형식의 대상 을 Work형식의 변수 에 할당 할 수 있 습 니 다.

조건 1 호출 시 studentworker(),컴 파일 러 는 인자 가 Student 형식 대상 이 어야 한 다 는 것 을 알려 줍 니 다.이 대상 은 Person 형식 대상 으로 성공 적 으로 전환 할 수 있 습 니 다.
조건 2 는 Woke 의뢰 정 의 를 다음 과 같이 조정 해 야 합 니 다.

delegate void WorkIn<in T>(T item);
의뢰 이름 을 WorkIn 으로 바 꾸 는 것 은 전후 의뢰 를 수정 하지 않 기 위 한 것 이 며,관건 은입 니 다.in 키 워드 를 추가 하여 이 일반 의뢰 의 유형 매개 변수 T 를 표시 하고 의뢰 방법의 매개 변수 로 만 사용 합 니 다.이 때 위의 프로그램 은 성공 적 으로 컴 파일 되 고 실 행 될 수 있 습 니 다.

delegate void WorkIn<in T>(T item);
class Program
 {
  static void Main(string[] args)
  {
   WorkIn<Person> woker = (p) => { Console.WriteLine(p.Name); };
   WorkIn<Student> student_worker = woker;
   student_worker(new Student() { Name="tom", Like="C#" });

  }
 }

형식 매개 변 수 를 하위 형식 으로 요구 하고 할당 형식 매개 변 수 를 부모 형식 값 으로 허용 하 는 경우 역 변 이 라 고 합 니 다.역 변 은 C\#에서 in 으로 범 형 을 표시 하 는 형식 매개 변 수 를 사용 해 야 합 니 다.역 변 은 역 변 이 라 고 하지만 형식적 으로 부모 대상 이 하위 변수 에 할당 하 는 것 처럼 보이 지만 실질 적 으로 방법 호출 시 매개 변수의 유형 전환 이다.Student s=new Person(),이것 은 불가능 하 다.이것 은 역 변 이 아니 라 잘못 이다.
위의 코드 가 만약 당신 이 아래 의 형식 으로 바 뀔 수 있다 면,당신 은 역 변 을 잊 을 수 있 고,본질은 현상 보다 더 중요 하 다.😀:

delegate void WorkIn<in T>(T item);
 class Program
 {
  static void Main(string[] args)
  {
   WorkIn<Person> woker = (p) => { Console.WriteLine(p.Name); };
   WorkIn<Student> student_worker = (s)=> { woker(s); };
   student_worker(new Student() { Name="tom", Like="C#" });
  }
 }
협동 하여 변화 하 다
 현재 우리 의 프로그램 수 요 를 수정 하고 Work 의뢰 를 실행 한 후에 Person 대상 으로 돌아 오 라 고 요구 합 니 다.다음 과 같 습 니 다.

 delegate T Work<T>(); 
 class Program
 {
  static void Main(string[] args)
  {
   Work<Person> worker = () => { return new Person(); };
   Work<Student> student_worker = () => { return new Student(); };

   worker = student_worker;
  }
 }

동상 worker=studentWorker 는 컴 파일 을 통과 할 수 없습니다.이 때 우리 의 목적 은:Work입 니 다.  student_work대신 woker 기능,studentwoker 가 실 행 된 후 Student 대상 을 되 돌려 줍 니 다.이것 은 Work의 요구 에 완전히 부합 합 니 다.
위의 목적 을 실현 하려 면 프로그램 역시 두 가지 측면 에서 처리 해 야 한다.
1.워 커()를 호출 할 때 실질 적 으로 실 행 된 것 은 student 이기 때 문 입 니 다.worker(),그래서 studentworker()실행 결과 에 너 지 는 woker 실행 후 돌아 오 는 형식 으로 바 뀔 수 있 습 니 다.
2.컴 파일 러 에 알려 야 합 니 다.여기 서 Work형식의 대상 을 Work형식의 변수 에 할당 할 수 있 습 니 다.
이때 조건 1.상기 코드 는 만족 되 었 습 니 다.조건 2 에 대해 일반적인 의뢰 Work 는 다음 과 같이 조정 해 야 합 니 다.
delegate T WorkOut();
의뢰 이름 을 WorkOut 으로 변경 하 는 것 도 전후 의뢰 를 수정 하지 않 는 것 으로 관건 은입 니 다.out 키 워드 를 추가 하여 이 일반 의뢰 의 유형 매개 변수 T 를 표시 하고 의뢰 방법의 반환 값 형식 으로 만 사용 합 니 다.이 때 위의 프로그램 은 성공 적 으로 컴 파일 되 고 실 행 될 수 있 습 니 다.

delegate T WorkOut<out T>();
class Program
 {
  static void Main(string[] args)
  {
   WorkOut<Person> worker = () => { return new Person(); };
   WorkOut<Student> student_worker = () => { return new Student(); };

   worker = student_worker;
   Person p = worker();
  }
 }

범 형 매개 변 수 를 부모 형식 으로 요구 하고 할당 형식 매개 변 수 를 하위 형식 값 으로 허용 하 는 경우 협 변 이 라 고 합 니 다.협 변 은 C\#에 out 로 범 형의 유형 인 자 를 표시 해 야 합 니 다.
주의:역 변,협 변 유형 설명 의 차이.이 끌 어 낸 정의 에 따라 역 변 하 는 형식 은 범 형(범 형 인터페이스,범 형 의뢰)에서 만 발생 할 수 있 으 며,협 변 하 는 코드 형식 은 비교적 많 지만 반드시 협 변 하 는 것 은 아니다.따라서 협 변 에 빨간색 으로 표시 하고 범 형 매개 변수 에 관 한 상황 이 어야 협 변 이다.다음 과 같은 상황 은 협 변 에 속 하지 않 는 다.

Person p = new Student();
위의 예제 코드 가 만약 당신 이 아래 의 형식 으로 바 뀔 수 있다 면,당신 도 협 변 을 잊 을 수 있 습 니 다.😀:

delegate T WorkOut<out T>();
class Program
 {
  static void Main(string[] args)
  {
   
   WorkOut<Student> student_worker = () => { return new Student(); };
   WorkOut<Person> worker = () => { return student_worker (); };
   Person p = worker();
  }
 }
위의 내용 을 통 해 역 변,협 변 은 사실 방법 파라미터,반환 값 유형의 전환 과 위탁 방법 에 대한 포장 일 뿐 이라는 것 을 알 수 있다.그 핵심 을 잡 고 여러 형식의 코드 를 보면 간단 하 다.
C\#4.0 에서 Action,Func 의 정 의 를 보고 역 변,협 변 을 더욱 깊이 이해 할 수 있 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기