>  기사  >  백엔드 개발  >  C#의 반공변성(Contravariance) 및 공분산(Covariance)에 대한 자세한 설명

C#의 반공변성(Contravariance) 및 공분산(Covariance)에 대한 자세한 설명

黄舟
黄舟원래의
2017-09-02 14:32:041238검색

이 글에서는 주로 C# 역산과 공분산 관련 정보를 자세하게 소개하고 있으니 참고할만한 가치가 있으니 관심 있는 분들은 참고하시기 바랍니다.

이 글에서는 델리게이터와 람다 식을 많이 사용합니다. 완전한 지식 시스템을 구축하는 데 도움이 되는 "위임 및 익명 위임" 및 "익명 위임 및 람다 표현식" 기사를 확인하세요.

C#의 탄생부터 발전과 성장까지의 과정에서 새로운 지식 포인트가 끊임없이 소개됩니다. 반공변성(Contravariance)과 공분산(Covariance)은 C#에 원래 있는 것이 아니며 나중에 소개될 것입니다. Java에도 반공변성(Contravariance)과 공변성(Covariance)이 존재합니다. 앞으로는 Java 반공변성(Contravariance)과 공분산(Covariance)에 대한 글을 쓸 예정입니다. 관심 있는 친구들은 주목해 보세요.

공분산과 공분산은 추상적이고 심오하게 들릴 수도 있지만 실제로는 매우 간단합니다. 아래 코드를 보세요:


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 List1f479e44f2c9bd2301ecbd2b69e4d7bf() 및 plist = new Lista8bdf01faaf42061e3f9f34321fc482d() 두 문장은 컴파일 오류를 생성합니다. 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());

다음 예제에서는 List plist = new List()가 할당을 허용한다고 가정합니다. plist 유형은 List 컬렉션입니다. List1f479e44f2c9bd2301ecbd2b69e4d7bf컬렉션입니다. plist.Add(new Person()), 실제 추가 작업은 List1f479e44f2c9bd2301ecbd2b69e4d7bf.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; //此处编译错误
  }
}

이전 이론적 지원에 따르면, Student_worker = Worker; 오류는 이해하기 쉽습니다. 그러나 여기서 우리 프로그램의 목적은 작업자가 Work1f479e44f2c9bd2301ecbd2b69e4d7bf로 기능하도록 하는 것입니다. 앞으로는 Student_worker(s)를 호출하면 실제로 waker(s)가 호출됩니다. 우리의 요구 사항을 충족하기 위해 프로그램은 두 가지 처리 측면을 수행해야 합니다.

1. Student_worker(s)를 호출할 때 실제로 실행되는 것은 waker(s)이므로 s 변수의 유형이 성공적이어야 합니다. waker 유형에 필요한 매개변수로 변환됩니다.

2. Work 유형의 개체를 Work 유형의 변수에 할당할 수 있음을 컴파일러에 알려야 합니다.

조건 1 Student_worker()를 호출할 때 컴파일러는 매개 변수가 Person 유형 객체로 성공적으로 변환될 수 있는 Student 유형 객체여야 한다는 메시지를 표시합니다.

조건 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 woker = (p) => { Console.WriteLine(p.Name); };
   WorkIn student_worker = woker;
   student_worker(new Student() { Name="tom", Like="C#" });

  }
 }

유형 매개변수는 하위 유형이어야 하고 할당 유형 매개변수는 상위 유형 값이 허용되는 상황을 반공변성이라고 합니다. C#의 반공변성에서는 제네릭의 형식 매개 변수를 표시해야 합니다. 반공변성을 반공변성이라고 부르지만 이는 형식적으로는 상위 클래스 객체가 하위 클래스 변수에 할당되는 것처럼 보입니다. 본질적으로 이는 메서드가 호출될 때 매개 변수의 유형 변환입니다. Student s = new Person(), 이는 불가능합니다. 이는 반공변이 아니며 오류입니다.

위 코드를 다음과 같은 형태로 변환할 수 있다면 반전은 잊어도 됩니다. 현상보다 본질이 더 중요합니다.

위 내용은 C#의 반공변성(Contravariance) 및 공분산(Covariance)에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.