C#编程基础之泛型方法解析(上)

黄舟
黄舟 原创
2017-02-06 16:53:34 849浏览

C#2.0引入了泛型这个特性,由于泛型的引入,在一定程度上极大的增强了C#的生命力,可以完成C#1.0时需要编写复杂代码才可以完成的一些功能。但是作为开发者,对于泛型可谓是又爱又恨,爱的是其强大的功能,以及该特性带来的效率的提升,恨的是泛型在复杂的时候,会呈现相当复杂的语法结构。


这种复杂不仅是对于初学者,对于一些有开发经验的.NET开发者,也是一个不那么容易掌握的特性。


接下来我们来了解一下C#2.0加入的特性:泛型。


一.泛型的基本特性概述


在实际项目开发中,任何API只要将object作为参数类型和返回类型使用,就可能在某个时候涉及强类型转换。提到强类型转换,估计很多开发者第一反应就是“效率”这个次,对于强类型的利弊主要看使用者使用的环境,天底下没有绝对的坏事,也没有绝对的好事,有关强类型的问题不是本次的重点,不做重点介绍。


泛型是CLR和C#提供的一种特殊机制,支持另一种形式的代码重用,即“算法重用”。泛型实现了类型和方法的参数化,泛型类型和方法也可以让参数告诉使用者使用什么类型。


泛型所带来的好处:更好的编译时检查,更多在代码中能直接表现的信息,更多的IDE支持,更好的性能。可能有人会疑问,为什么泛型会带来这么多好处,使用一个不能区分不同类型的常规API,相当于在一个动态环境中访问那个API。

CLR允许创建泛型引用和泛型值类型,但是不允许创建泛型枚举,并且CLR允许创建泛型接口和泛型委托,CLR允许在引用类型、值类型或接口中定义泛型方法。定义泛型类型或方法时,为类型指定了任何变量(如:T)都称为类型参数。(T是一个变量名,在源代码中能够使用一个数据类型的任何位置,都可以使用T)在C#中泛型参数变量要么成为T,要么至少一大写T开头。

二.泛型类、泛型接口和泛型委托概述

1.泛型类

泛型类型仍然是类型,所以可以从任何类型派生。使用一个泛型类型并指定类型实参时,实际是在CLR中定义一个新类型对象,新类型对象是从泛型派生自的那个类型派生的。

使用泛型类型参数的一个方法在基尼险那个JIT编译时,CLR获取IL,用指定的类型实参进行替换,然后创建恰当的本地代码。

如果没有为泛型类型参数提供类型实参,那就么就是未绑定泛型类型。如果指定了类型实参,该类型就是已构造类型。

已构造类型可以是开发或封闭的,开发类型还包含一个类ixngcanshu,而封闭类型则不是开发的,类型的每个部分都是明确的。所有代码实际都是在一个封闭的已构造类型的上下文中执行。

泛型类在.NET的应用主要在集合类中,大多数集合类在System.Collections.Generic和System.Collections.ObjectModel类中。下面简单的介绍一种泛型集合类:

(1).SynchronizedCollection:提供一个线程安全集合,其中包含泛型参数所指定类型的对象作为元素.

[ComVisible(false)]
public class SynchronizedCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
  {
    /// <summary>
    /// 初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。
    /// </summary>
    public SynchronizedCollection();
    /// <summary>
    /// 通过用于对线程安全集合的访问进行同步的对象来初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。
    /// </summary>
    /// <param name="syncRoot">用于对线程安全集合的访问进行同步的对象。</param><exception cref="T:System.ArgumentNullException">
    <paramref name="syncRoot"/> 为 null。</exception>
    public SynchronizedCollection(object syncRoot);
    /// <summary>
    /// 使用指定的可枚举元素列表和用于对线程安全集合的访问进行同步的对象来初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。
    /// </summary>
    /// <param name="syncRoot">用于对线程安全集合的访问进行同步的对象。</param>
    <param name="list">用于初始化线程安全集合的元素的 <see cref="T:System.Collections.Generic.IEnumerable`1"/> 集合。</param>
    <exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/> 或 <paramref name="list"/> 为 null。</exception>
    public SynchronizedCollection(object syncRoot, IEnumerable<T> list);
    /// <summary>
    /// 使用指定的元素数组和用于对线程安全集合的访问进行同步的对象来初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。
    /// </summary>
    /// <param name="syncRoot">用于对线程安全集合的访问进行同步的对象。</param>
    <param name="list">用于初始化线程安全集合的 <paramref name="T"/> 类型元素的 <see cref="T:System.Array"/>。</param>
    <exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/> 或 <paramref name="list"/> 为 null。</exception>
    public SynchronizedCollection(object syncRoot, params T[] list);
    /// <summary>
    /// 将项添加到线程安全只读集合中。
    /// </summary>
    /// <param name="item">要添加到集合的元素。</param>
    <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception>
    public void Add(T item);
    /// <summary>
    /// 从集合中移除所有项。
    /// </summary>
    public void Clear();
    /// <summary>
    /// 从特定索引处开始,将集合中的元素复制到指定的数组。
    /// </summary>
    /// <param name="array">从集合中复制的 <paramref name="T "/>类型元素的目标 <see cref="T:System.Array"/>。</param>
    <param name="index">复制开始时所在的数组中的从零开始的索引。</param>
    public void CopyTo(T[] array, int index);
    /// <summary>
    /// 确定集合是否包含具有特定值的元素。
    /// </summary>
    /// 
    /// <returns>
    /// 如果在集合中找到元素值,则为 true;否则为 false。
    /// </returns>
    /// <param name="item">要在集合中定位的对象。</param>
    <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception>
    public bool Contains(T item);
    /// <summary>
    /// 返回一个循环访问同步集合的枚举数。
    /// </summary>
    /// 
    /// <returns>
    /// 一个 <see cref="T:System.Collections.Generic.IEnumerator`1"/>,用于访问集合中存储的类型的对象。
    /// </returns>
    public IEnumerator<T> GetEnumerator();
    /// <summary>
    /// 返回某个值在集合中的第一个匹配项的索引。
    /// </summary>
    /// 
    /// <returns>
    /// 该值在集合中的第一个匹配项的从零开始的索引。
    /// </returns>
    /// <param name="item">从集合中移除所有项。</param><exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 
    <paramref name="T"/>。</exception>
    public int IndexOf(T item);
    /// <summary>
    /// 将一项插入集合中的指定索引处。
    /// </summary>
    /// <param name="index">要从集合中检索的元素的从零开始的索引。</param><param name="item">要作为元素插入到集合中的对象。</param>
    <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception>
    <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception>
    public void Insert(int index, T item);
    /// <summary>
    /// 从集合中移除指定项的第一个匹配项。
    /// </summary>
    /// 
    /// <returns>
    /// 如果从集合中成功移除了项,则为 true;否则为 false。
    /// </returns>
    /// <param name="item">要从集合中移除的对象。</param>
    public bool Remove(T item);
    /// <summary>
    /// 从集合中移除指定索引处的项。
    /// </summary>
    /// <param name="index">要从集合中检索的元素的从零开始的索引。</param>
    <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception>
    public void RemoveAt(int index);
    /// <summary>
    /// 从集合中移除所有项。
    /// </summary>
    protected virtual void ClearItems();
    /// <summary>
    /// 将一项插入集合中的指定索引处。
    /// </summary>
    /// <param name="index">集合中从零开始的索引,在此处插入对象。</param><param name="item">要插入到集合中的对象。</param>
    <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception>
    <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception>
    protected virtual void InsertItem(int index, T item);
    /// <summary>
    /// 从集合中移除指定 <paramref name="index"/> 处的项。
    /// </summary>
    /// <param name="index">要从集合中检索的元素的从零开始的索引。</param>
    <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception>
    protected virtual void RemoveItem(int index);
    /// <summary>
    /// 使用另一项替换指定索引处的项。
    /// </summary>
    /// <param name="index">要替换的对象的从零开始的索引。</param><param name="item">要替换的对象。</param>
    <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception>
    protected virtual void SetItem(int index, T item);
    /// <summary>
    /// 返回一个循环访问同步集合的枚举数。
    /// </summary>
    /// 
    /// <returns>
    /// 一个 <see cref="T:System.Collections.Generic.IEnumerator`1"/>,用于访问集合中存储的类型的对象。
    /// </returns>
    IEnumerator IEnumerable.GetEnumerator();
    /// <summary>
    /// 从特定索引处开始,将集合中的元素复制到指定的数组。
    /// </summary>
    /// <param name="array">从集合中复制的 <paramref name="T"/> 类型元素的目标 <see cref="T:System.Array"/>。</param>
    <param name="index">复制开始时所在的数组中的从零开始的索引。</param>
    void ICollection.CopyTo(Array array, int index);
    /// <summary>
    /// 向集合中添加一个元素。
    /// </summary>
    /// 
    /// <returns>
    /// 新元素的插入位置。
    /// </returns>
    /// <param name="value">要添加到集合中的对象。</param>
    int IList.Add(object value);
    /// <summary>
    /// 确定集合是否包含具有特定值的元素。
    /// </summary>
    /// <returns>
    /// 如果在集合中找到元素 <paramref name="value"/>,则为 true;否则为 false。
    /// </returns>
  /// <param name="value">要在集合中定位的对象。</param><exception cref="T:System.ArgumentException"><paramref name="value"/> 不是集合所含类型的对象。</exception>
    bool IList.Contains(object value);
    /// <summary>
    /// 确定集合中某个元素的从零开始的索引。
    /// </summary>
    /// 
    /// <returns>
    /// 如果在集合中找到,则为 <paramref name="value"/> 的索引;否则为 -1。
    /// </returns>
    /// <param name="value">集合中要确定其索引的元素。</param>
    int IList.IndexOf(object value);
    /// <summary>
    /// 将某个对象插入到集合中的指定索引处。
    /// </summary>
    /// <param name="index">从零开始的索引,将在该位置插入 <paramref name="value"/>。</param><param name="value">要在集合中插入的对象。</param>
    <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception>
    <exception cref="T:System.ArgumentException">设置的 <paramref name="value"/> 为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception>
    void IList.Insert(int index, object value);
    /// <summary>
    /// 从集合中移除作为元素的指定对象的第一个匹配项。
    /// </summary>
    /// <param name="value">要从集合中移除的对象。</param>
    void IList.Remove(object value);
  }

(2).KeyedByTypeCollection:提供一个集合,该集合的项是用作键的类型。

[__DynamicallyInvokable]
  public class KeyedByTypeCollection<TItem> : KeyedCollection<Type, TItem>
  {
    /// <summary>
    /// 初始化 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 类的新实例。
    /// </summary>
    public KeyedByTypeCollection();
    /// <summary>
    /// 根据指定的对象枚举初始化 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 类的新实例。
    /// </summary>
    /// <param name="items">泛型类型 <see cref="T:System.Object"/> 的 <see cref="T:System.Collections.Generic.IEnumerable`1"/>,用于初始化集合。</param>
    <exception cref="T:System.ArgumentNullException"><paramref name="items"/> 为 null。</exception>
    public KeyedByTypeCollection(IEnumerable<TItem> items);
    /// <summary>
    /// 返回集合中第一个具有指定类型的项。
    /// </summary>
    /// 
    /// <returns>
    /// 如果为引用类型,则返回类型 <paramref name="T"/> 的对象;如果为值类型,则返回类型 <paramref name="T"/> 的值。 
    如果集合中不包含类型 <paramref name="T"/> 的对象,则返回类型的默认值:如果是引用类型,默认值为 null;如果是值类型,默认值为 0。
    /// </returns>
    /// <typeparam name="T">要在集合中查找的项的类型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public T Find<T>();
    /// <summary>
    /// 从集合中移除具有指定类型的对象。
    /// </summary>
    /// 
    /// <returns>
    /// 从集合中移除的对象。
    /// </returns>
    /// <typeparam name="T">要从集合中移除的项的类型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public T Remove<T>();
    /// <summary>
    /// 返回 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 中包含的类型 <paramref name="T"/> 的对象的集合。
    /// </summary>
    /// 
    /// <returns>
    /// 一个类型 <paramref name="T"/> 的 <see cref="T:System.Collections.ObjectModel.Collection`1"/>,包含来自原始集合的类型 <paramref name="T"/> 的对象。
    /// </returns>
    /// <typeparam name="T">要在集合中查找的项的类型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public Collection<T> FindAll<T>();
    /// <summary>
    /// 从集合中移除所有具有指定类型的元素。
    /// </summary>
    /// 
    /// <returns>
    /// <see cref="T:System.Collections.ObjectModel.Collection`1"/>,包含来自原始集合的类型 <paramref name="T"/> 的对象。
    /// </returns>
    /// <typeparam name="T">要从集合中移除的项的类型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public Collection<T> RemoveAll<T>();
    /// <summary>
    /// 获取集合中包含的某个项的类型。
    /// </summary>
    /// 
    /// <returns>
    /// 集合中指定的 <paramref name="item"/> 的类型。
    /// </returns>
    /// <param name="item">集合中要检索其类型的项。</param><exception cref="T:System.ArgumentNullException"><paramref name="item"/> 为 null。</exception>
    [__DynamicallyInvokable]
    protected override Type GetKeyForItem(TItem item);
    /// <summary>
    /// 在集合中的特定位置插入一个元素。
    /// </summary>
    /// <param name="index">从零开始的索引,应在该位置插入 <paramref name="item"/>。</param><param name="item">要在集合中插入的对象。</param>
    <exception cref="T:System.ArgumentNullException"><paramref name="item"/> 为 null。</exception>
    [__DynamicallyInvokable]
    protected override void InsertItem(int index, TItem item);
    /// <summary>
    /// 使用一个新对象替换指定索引处的项。
    /// </summary>
    /// <param name="index">要替换的 <paramref name="item"/> 的从零开始的索引。</param><param name="item">要添加到集合中的对象。</param>
    <exception cref="T:System.ArgumentNullException"><paramref name="item"/> 为 null。</exception>
    [__DynamicallyInvokable]
    protected override void SetItem(int index, TItem item);
  }

CLR支持泛型委托,目的是保证任何类型的对象都能以一种类型安全的方式传给一个回调方法。泛型委托允许一个孩子类型实例在传给一个回调方法时不执行任何装箱处理。委托时机只提供了4个方法:一个构造器,一个Invlke方法,一个BeginInvoke方法和一个EndInvoke方法。如果定义的一个委托类型指定了类型参数,编译器会定义委托类的方法,用指定的类型参数替换方法的参数类型和值类型。

以上就是C#编程基础之泛型方法解析(上)的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!


声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。