C#泛型(二)

四、類型參數的約束

若要檢查表中的一個元素,以確定它是否合法或是否可以與其他元素相比較,那麼編譯器必須保證:客戶代碼中可能出現的所有類型參數,都要支持所需調用的操作或方法。這種保證是通過在泛型類的定義中,應用一個或多個約束而得到的。一個約束類型是一種基類約束,它通知編譯器,只有這個類型的對象或從這個類型派生的對象,可被用作類型參數。一旦編譯器得到這樣的保證,它就允許在泛型類中調用這個類型的方法。上下文關鍵字where用以實現約束。下面的示例代碼說明了應用基類約束,爲MyList類增加功能。

public class Employee
{
 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; }
        }

    }
}
class MyList<T> where T: Employee
{
 //Rest of class as before.
  public T FindFirstOccurrence(string s)
  {
   T t = null;
   Reset();
   while (HasItems())
   {
      if (current != null)
      {
//The constraint enables this:
         if (current.Data.Name == s)
         {
            t = current.Data;
            break;
         }
         else
         {
            current = current.Next;
         }
      } //end if
   } // end while
  return t;
  }
}

約束使得泛型類能夠使用Employee.Name屬性,因爲所有爲類型T的元素,都是一個Employee對象或是一個繼承自Employee的對象。

同一個類型參數可應用多個約束。約束自身也可以是泛型類,如下:

class MyList where T: Employee, IEmployee, IComparable, new()
{…}

這裏寫圖片描述

類型參數的約束,增加了可調用的操作和方法的數量。這些操作和方法受約束類型及其派生層次中的類型的支持。因此,設計泛型類或方法時,如果對泛型成員執行任何賦值以外的操作,或者是調用System.Object中所沒有的方法,就需要在類型參數上使用約束。

無限制類型參數的一般用法
沒有約束的類型參數,如公有類MyClass{…}中的T, 被稱爲無限制類型參數(unbounded type parameters)。無限制類型參數有以下規則:
l 不能使用運算符 != 和 == ,因爲無法保證具體的類型參數能夠支持這些運算符。
l 它們可以與System.Object相互轉換,也可顯式地轉換成任何接口類型。
l 可以與null比較。如果一個無限制類型參數與null比較,當此類型參數爲值類型時,比較的結果總爲false。

無類型約束
當約束是一個泛型類型參數時,它就叫無類型約束(Naked type constraints)。當一個有類型參數成員方法,要把它的參數約束爲其所在類的類型參數時,無類型約束很有用。如下例所示:

class List
{
//…
void Add(List items) where U:T {…}
}

在上面的示例中, Add方法的上下文中的T,就是一個無類型約束;而List類的上下文中的T,則是一個無限制類型參數。

無類型約束也可以用在泛型類的定義中。注意,無類型約束一定也要和其它類型參數一起在尖括號中聲明:
//naked type constraint
public class MyClass

//創建一個類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace WindowsFormsApplication1
{
 public   class Class1<T> where T:int
    {
     T a;
     public T Add(T b)
     {
         return b;
     }
    }
}
//主程式
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                Class1<string> ss = new Class1<string>();
                ss.Add("123");
            }
            catch(Exception ex)
            {

            }

        }
    }
}

注意這種寫法會導致錯誤,以爲加了約束條件。報錯如下:
這裏寫圖片描述
由於加了約束條件會導致,這種錯誤因爲類型不一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章