C# 泛型(Generic)

什么是泛型?

泛型是一种编程技术,它允许你编写可以处理多种数据类型的代码。通过使用泛型,你可以创建一组可以在不同场景下使用的类、接口和方法,而不必为每种数据类型重写代码。

例如,假设你需要一个存储整数的列表。你可以使用 List<int>,但如果你还需要一个存储字符串的列表,那么你就需要创建一个 List<string>。使用泛型,你可以创建一个可以处理任何数据类型的通用列表,然后根据需要指定具体的数据类型。

泛型的好处

类型安全

使用泛型可以提高代码的类型安全性。由于你指定了数据类型,编译器可以在编译时检查类型错误,从而减少运行时的错误。

可重用性

泛型提高了代码的可重用性。你可以编写一个适用于多种数据类型的通用类或方法,而无需重复编写代码。

性能优化

使用泛型可以避免不必要的装箱和拆箱操作,从而提高程序性能。例如,在使用非泛型集合(如 ArrayList)时,所有对象都必须被装箱和拆箱,这会降低性能。

泛型的基本用法

泛型类

你可以创建一个泛型类,该类可以处理任意类型的数据。以下是一个简单的泛型类示例:

-- -------------------- ---- -------
------ ----- ------
-
    ------- - -----

    ------ ----- -----
    -
        --------- - -----
    -

    ------ - ---------
    -
        ------ -----
    -

    ------ ---- --------- -----
    -
        --------- - -----
    -
-

在这个例子中,T 是一个类型参数,表示任何类型。你可以使用这个类来创建存储不同类型数据的实例:

泛型方法

除了泛型类,你还可以创建泛型方法。这些方法可以在调用时指定类型参数。以下是一个简单的泛型方法示例:

-- -------------------- ---- -------
------ ------ - ----------- -- - -- ----- - - --------------
-
    -- --------------- - --
    -
        ------ --
    -
    ----
    -
        ------ --
    -
-

在这个例子中,T 必须实现 IComparable<T> 接口,这样我们才能比较两个对象。你可以像下面这样使用这个方法:

泛型约束

泛型约束允许你限制类型参数的类型。例如,你可以指定类型参数必须实现某个接口或继承自某个基类。以下是一些常见的泛型约束:

  • where T : struct:类型参数必须是值类型。
  • where T : class:类型参数必须是引用类型。
  • where T : new():类型参数必须有一个无参构造函数。
  • where T : IComparable<T>:类型参数必须实现 IComparable<T> 接口。

例如,以下是一个带有约束的泛型类示例:

-- -------------------- ---- -------
------ ----- --------- ----- - - ---------
-
    ------ ---- ----- --------
    -
        -------------------
    -
-

------ --------- ---------
-
    ---- -----------
-

------ ----- ------------- - ---------
-
    ------ ---- ----------
    -
        -------------------------- -- -------------
    -
-

-- -----
--------------------- ------ - --- ------------------------
-------------- -----------------

在这个例子中,Logger<T> 类的类型参数 T 必须实现 ILoggable 接口。因此,只有实现了 ILoggable 接口的类型才能用作 Logger<T> 的类型参数。

泛型接口

泛型接口允许你定义可以处理任意类型数据的接口。以下是一个简单的泛型接口示例:

你可以创建一个实现了泛型接口的类:

-- -------------------- ---- -------
------ ----- -------- - ---------
-
    ------- ------- ----- - --- ----------

    ------ ---- ------ -----
    -
        ----------------
    -

    ------ - -----
    -
        -- ------------ -- --
        -
            ----- --- -------------------------------- -- ---------
        -
        - ---- - ----------------- - ---
        -------------------------- - ---
        ------ -----
    -

    ------ ---- ------- -- ----------- -- --
-

泛型事件

你也可以在泛型类中定义泛型事件。以下是一个示例:

-- -------------------- ---- -------
------ ----- -----------------
-
    ------ ----- --------------- ------------

    --------- ------- ---- --------------- -----
    -
        ------------------------- ------
    -

    ------ ---- -------------- -----
    -
        --------------------
    -
-

------ ----- ----------- - ---------
-
    ------ --- ----- - ---- ---- -
-

------ ----- -------
-
    ------ ------ ---- ------
    -
        --------------------------- --------- - --- ------------------------------

        --------------------- -- -------- -- --
        -
            ------------------------- ------- --- ------------
        --

        -------------------------- ----------- - ----- - -- ---
    -
-

在这个例子中,EventPublisher<T> 类定义了一个泛型事件 DataChanged,它接受类型参数 T。你可以为这个事件订阅不同的处理程序,并传递不同的数据类型。

泛型的局限性和注意事项

虽然泛型提供了许多好处,但在使用泛型时也需要注意一些问题:

泛型类型参数的限制

虽然你可以使用泛型类型参数来创建非常灵活的类和方法,但某些操作可能仍然受限于类型参数的限制。例如,你不能对类型参数执行某些操作,除非你知道它支持这些操作。因此,使用泛型约束可以帮助你确保类型参数满足特定的要求。

性能考虑

虽然泛型可以提高性能,特别是在避免装箱和拆箱操作方面,但在某些情况下,过度使用泛型可能会导致性能下降。因此,在设计泛型类和方法时,应仔细权衡其性能影响。

复杂性

泛型可以增加代码的复杂性,特别是对于不熟悉泛型概念的开发者。因此,在使用泛型时,应尽量保持代码的简洁性和易读性。

总结

泛型是 C# 中一个强大且灵活的特性,它可以提高代码的类型安全性、可重用性和性能。通过使用泛型,你可以创建适用于多种数据类型的通用类和方法,而无需重复编写代码。希望本章的内容能够帮助你更好地理解和使用泛型。

上一篇: C# 集合(Collection)
下一篇: C# 匿名方法
纠错
反馈