ホームページ  >  記事  >  バックエンド開発  >  C# の where 型制約についての詳細なグラフィックとテキストの紹介

C# の where 型制約についての詳細なグラフィックとテキストの紹介

黄舟
黄舟オリジナル
2017-03-03 13:17:471334ブラウズ

型パラメータの制約 (C# プログラミング ガイド)

Visual Studio 2005





その他のバージョン

ジェネリッククラスを定義する場合、Sideを指定できますコードは、クラスをインスタンス化するときに型パラメーターに使用される型に制限を課すことができます。クライアント コードが制約で許可されていない型を使用してクラスをインスタンス化しようとすると、コンパイル時エラーが発生します。これらの制限は制約と呼ばれます。制約は、where コンテキスト キーワードを使用して指定されます。次の表に、6 種類の制約を示します。

制約 説明

T: 構造体

型パラメータは値型である必要があります。 Nullable を除く任意の値の型を指定できます。詳細については、「Null 許容型の使用 (C#)」を参照してください。 プログラミングガイド)。

T: クラス

の型パラメーターは、クラス、インターフェイス、デリゲート、または配列型を含む参照型である必要があります。

T: new()

型パラメーターにはパラメーターのないパブリック コンストラクターが必要です。他の制約と一緒に使用する場合、new() 制約を最後に指定する必要があります。

T: f1f2a1b68c7ad2fcc88f1b5cb06d6b8a

型パラメータは、指定された基本クラス、または指定された基本クラスから派生したものである必要があります。

T:

type パラメータは、指定されたインターフェイスであるか、指定されたインターフェイスを実装する必要があります。複数のインターフェイス制約を指定できます。制約インターフェイスは汎用にすることもできます。

T: U

T に提供される型パラメーターは、 U に提供されるパラメーターであるか、 U に提供されるパラメーターから派生する必要があります。これはネイキッドタイプ制約と呼ばれます。


制約を使用する理由


汎用リスト内の項目をチェックしてそれが有効かどうかを確認したり、他の項目と比較したりする場合、コンパイラーは、それが必要であることをある程度のレベルで保証する必要があります。呼び出される演算子またはメソッドは、クライアント コードで指定される任意の型パラメータによってサポートされます。この保証は、ジェネリック クラス定義に 1 つ以上の制約を適用することによって得られます。たとえば、基本クラス制約は、この型のオブジェクトまたはこの型から派生したオブジェクトのみが型パラメーターとして使用できることをコンパイラーに指示します。コンパイラがこの保証を取得すると、ジェネリック クラスでその型のメソッドを呼び出すことができるようになります。制約は、コンテキスト キーワード where を使用して適用されます。次のコード例は、GenericList8742468051c85b06f0a0af9e3e506b5c クラスに基本クラスの制約を追加する方法を示しています (ジェネリック入門 (C#) プログラミングガイド)) 関数。

public class Employee
{
    private string name;
    private int id;


    public Employee(string s, int i)
    {
        name = s;
        id = i;
    }


    public string Name
    {
        get { return name; }
        set { name = value; }
    }


    public int ID
    {
        get { return id; }
        set { id = value; }
    }
}


public class GenericList<T> where T : Employee
{
    private class Node
    {
        private Node next;
        private T data;


        public Node(T t)
        {
            next = null;
            data = t;
        }


        public Node Next
        {
            get { return next; }
            set { next = value; }
        }


        public T Data
        {
            get { return data; }
            set { data = value; }
        }
    }


    private Node head;


    public GenericList() //constructor
    {
        head = null;
    }


    public void AddHead(T t)
    {
        Node n = new Node(t);
        n.Next = head;
        head = n;
    }


    public IEnumerator<T> GetEnumerator()
    {
        Node current = head;


        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }


    public T FindFirstOccurrence(string s)
    {
        Node current = head;
        T t = null;


        while (current != null)
        {
            //The constraint enables access to the Name property.
            if (current.Data.Name == s)
            {
                t = current.Data;
                break;
            }
            else
            {
                current = current.Next;
            }
        }
        return t;
    }
}

制約タイプのパラメーターを使用すると、制約タイプとその継承階層内のすべてのタイプでサポートされる、許可される操作とメソッド呼び出しの数を増やすことができます。したがって、ジェネリック クラスまたはメソッドを設計するときに、ジェネリック メンバーへの単純な割り当て以外の操作を行う場合、または System.Object でサポートされていないメソッドを呼び出す場合は、型パラメーターに制約を適用する必要があります。

where T : class 制約を適用する場合、型パラメーターに == および != 演算子を使用しないことをお勧めします。これらの演算子は参照の同一性のみをテストし、値の同一性をテストしないためです。これは、これらの演算子がパラメーターとして使用される型でオーバーロードされている場合にも当てはまります。以下のコードは、String クラスが == 演算子をオーバーロードしているにもかかわらず、出力は次のようになります。 間違い。

C#

public static void OpTest<T>(T s, T t) where T : class
{
    System.Console.WriteLine(s == t);
}
static void Main()
{
    string s1 = "foo";
    System.Text.StringBuilder sb = new System.Text.StringBuilder("foo");
    string s2 = sb.ToString();
    OpTest<string>(s1, s2);
}

その理由は、コンパイラーは T が参照型であることをコンパイル時にのみ認識するため、すべての参照型に対して有効なデフォルトの演算子を使用する必要があるためです。値の同等性をテストする必要がある場合、推奨されるアプローチは、where T : IComparable8742468051c85b06f0a0af9e3e506b5c 制約の両方を適用し、ジェネリック クラスの構築に使用される任意のクラスにインターフェイスを実装することです。

非バインド型パラメータ



制約のない型パラメータ (パブリック クラス SampleClass8742468051c85b06f0a0af9e3e506b5c{} の T など) は、非バインド型パラメータと呼ばれます。非バインド型パラメーターには次の規則があります:

  • は、具象型パラメーターがこれらの演算子をサポートする保証がないため、!= および == 演算子と一緒に使用できません。

  • System.Objectとの間で変換したり、任意のインターフェイス型に明示的に変換したりできます。

  • それらを null と比較できます。バインドされていないパラメーターを null と比較する場合、型パラメーターが値型の場合、比較は常に false を返します。

ネイキッドタイプ制約



制約として使用されるジェネリック型パラメーターはネイキッドタイプ制約と呼ばれます。裸の型制約は、次の例に示すように、独自の型パラメーターを持つメンバー関数がそのパラメーターを包含型の型パラメーターに制約する必要がある場合に役立ちます。

C#

class List<T>
{
    void Add<U>(List<U> items) where U : T {/*...*/}
}

上の例では、 T は、Addメソッドのコンテキストではネイキッド型制約であり、Listクラスのコンテキストではアンバインド型パラメータです。

裸の型制約は、ジェネリック クラス定義でも使用できます。裸の型制約は、他の型パラメータとともに山括弧内で宣言されている必要があることに注意してください:

C#
//naked type constraint
public class SampleClass<T, U, V> where T : V { }

コンパイラは、裸の型制約が次から派生すると想定するだけであるため、ジェネリック クラスの裸の型制約の用途は非常に限られています。 システム .Object 以外の仮定は行われません。 2 つの型パラメーター間の継承関係を強制する場合は、ジェネリック クラスでネイキッド型制約を使用できます。

上記は、C# の where 型制約のグラフィックとテキストの詳細です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。


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