泛型(四)

風靈使發表於2019-01-12

泛型方法(C# 程式設計指南)

泛型方法是通過型別引數宣告的方法,如下所示:

static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}

如下示例演示使用型別引數的 int 呼叫方法的一種方式:

public static void TestSwap()
{
    int a = 1;
    int b = 2;

    Swap<int>(ref a, ref b);
    System.Console.WriteLine(a + " " + b);
}

還可省略型別引數,編譯器將推斷型別引數。 如下 Swap 呼叫等效於之前的呼叫:

Swap(ref a, ref b);

型別推理的相同規則適用於靜態方法和例項方法。 編譯器可基於傳入的方法引數推斷型別引數;而無法僅根據約束或返回值推斷型別引數。 因此,型別推理不適用於不具有引數的方法。 型別推理髮生在編譯時,之後編譯器嘗試解析過載的方法簽名。 編譯器將型別推理邏輯應用於共用同一名稱的所有泛型方法。 在過載解決方案步驟中,編譯器僅包含在其上型別推理成功的泛型方法。

在泛型類中,非泛型方法可訪問類級別型別引數,如下所示:

class SampleClass<T>
{
    void Swap(ref T lhs, ref T rhs) { }
}

如果定義一個具有與包含類相同的型別引數的泛型方法,則編譯器會生成警告 CS0693,因為在該方法範圍內,向內 T 提供的引數會隱藏向外 T 提供的引數。 如果需要使用型別引數(而不是類例項化時提供的引數)呼叫泛型類方法所具備的靈活性,請考慮為此方法的型別引數提供另一識別符號,如下方示例中 GenericList2<T> 所示。


class GenericList<T>
{
    // CS0693
    void SampleMethod<T>() { }
}

class GenericList2<T>
{
    //No warning
    void SampleMethod<U>() { }
}

使用約束在方法中的型別引數上實現更多專用操作。 此版 Swap<T> 現名為 SwapIfGreater<T>,僅可用於實現 IComparable<T> 的型別引數。

void SwapIfGreater<T>(ref T lhs, ref T rhs) where T : System.IComparable<T>
{
    T temp;
    if (lhs.CompareTo(rhs) > 0)
    {
        temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
}

泛型方法可過載在數個泛型引數上。 例如,以下方法可全部位於同一類中:

void DoWork() { }
void DoWork<T>() { }
void DoWork<T, U>() { }

泛型和陣列(C# 程式設計指南)

在 C# 2.0 和更高版本中,下限為零的單維陣列自動實現 IList<T>。 這可使你建立可使用相同程式碼迴圈訪問陣列和其他集合型別的泛型方法。 此技術的主要用處在於讀取集合中的資料。 IList<T> 介面無法用於新增元素或從陣列刪除元素。 如果在此上下文中嘗試對陣列呼叫 IList<T> 方法(例如 RemoveAt),則會引發異常。

如下程式碼示例演示具有 IList<T> 輸入引數的單個泛型方法如何可迴圈訪問列表和陣列(此例中為整數陣列)。


class Program
{
    static void Main()
    {
        int[] arr = { 0, 1, 2, 3, 4 };
        List<int> list = new List<int>();

        for (int x = 5; x < 10; x++)
        {
            list.Add(x);
        }

        ProcessItems<int>(arr);
        ProcessItems<int>(list);
    }

    static void ProcessItems<T>(IList<T> coll)
    {
        //IsReadOnly為陣列返回True,為List返回False。
        System.Console.WriteLine
            ("IsReadOnly returns {0} for this collection.",
            coll.IsReadOnly);

        //以下語句導致陣列的執行時異常,但不會導致List。
        //coll.RemoveAt(4);

        foreach (T item in coll)
        {
            System.Console.Write(item.ToString() + " ");
        }
        System.Console.WriteLine();
    }
}



相關文章