ホームページ  >  記事  >  バックエンド開発  >  C# の反変性と共分散の詳細な説明

C# の反変性と共分散の詳細な説明

黄舟
黄舟オリジナル
2017-09-02 14:32:041280ブラウズ

この記事では主に C# の反転と共分散の関連情報を詳しく紹介します。興味のある方は参考にしてください。

この記事では、これらの式に慣れていない場合は、完全な知識システムの構築に役立つように、私の記事「委任と匿名委任」と「匿名委任とラムダ式」を参照してください。

C# の誕生から開発、成長に至る過程では、常に新しい知識ポイントが導入されます。反変性と共分散は C# 独自のものではないため、後で導入します。反変性と共分散性は Java にも存在します。今後、Java の反変性と共分散についても記事を書きますので、興味のある方は注目してください。

反変性と共分散は抽象的で奥深いように聞こえるかもしれませんが、実際は非常に単純です。以下のコードを見てください:


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() という 2 つの文によりコンパイル エラーが発生します。 Person は Student/Teacher の親クラスですが、List0833d296851a1e081f2175a4cbfa7135 型は List 型の親クラスではないため、上記の代入ステートメントは型変換エラーを報告します。

上記のような代入操作は、C# 4.0 より前では許可されませんでした。許可されない理由としては、タイプ セーフティが主な要因です。以下のサンプルコードを見てください:


List<Person> plist = new List<Student>();
plist.Add(new Person());
plist.Add(new Student());
plist.Add(new Teacher());

次の例では、List0833d296851a1e081f2175a4cbfa7135 plist = new List1f479e44f2c9bd2301ecbd2b69e4d7bf() が代入を許可していることを前提としています。リスト831e8d2b501ee839f1f0bc03107c10c9コレクションです。 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; の誤りは理解しやすいです。ただし、ここでのプログラムの目的は、worker を Work1f479e44f2c9bd2301ecbd2b69e4d7bf として機能させることです。将来、student_worker を呼び出すと、実際には waker が呼び出されます。私たちのニーズを満たすために、プログラムは 2 つの側面の処理を実行する必要があります:

1. Student_worker(s) を呼び出すとき、実際に実行されるのは waker(s) であるため、s 変数の型が正常である必要があります。 waker タイプに必要なパラメータに変換されます。

2. Work0833d296851a1e081f2175a4cbfa7135 型のオブジェクトを Work1f479e44f2c9bd2301ecbd2b69e4d7bf 型の変数に代入できることをコンパイラーに伝える必要があります。

条件 1student_worker() を呼び出すと、コンパイラーは、パラメーターが Student タイプのオブジェクトである必要があることを要求します。これは、person タイプのオブジェクトに正常に変換できます。

条件 2 では、次のように Woke デリゲート定義を調整する必要があります:


delegate void WorkIn<in T>(T item);

デリゲート名を WorkIn に変更することは、変更前と変更後のデリゲートを区別するためです。重要な点は 6f9802517dbf33d9eaf907870b00da1a です。 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# の反変性と共分散の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。