zoukankan      html  css  js  c++  java
  • 泛型系列<3>:获取泛型的类型

    4.3 获取泛型的类型

    问题

    您需要在运行时获得一个泛型类型实例的Type对象。

    解决方案

    在使用typeof操作符时提供类型参数;使用类型参数实例化的泛型类型,用GetType()方法。

    声明一个一般类型和一个泛型类型如下:

    public class Simple

    {

        public Simple()

        {

        }

    }

     

    public class SimpleGeneric<T>

    {

        public SimpleGeneric()

        {

        }

    }

    使用typeof操作符和简单类型的名称就可以在运行时获得简单类型的类型。对于泛型类型来说,在调用typeof时类型参数必须要提供,但是简单类型实例和泛型类型实例都可以使用相同的方式来调用GetType()

        Simple s = new Simple();

        Type t = typeof(Simple);

        Type alsoT = s.GetType();

        //提供类型参数就才可以获得类型实例

        Type gtInt = typeof(SimpleGeneric<int>);

        Type gtBool = typeof(SimpleGeneric<bool>);

        Type gtString = typeof(SimpleGeneric<string>);

        // 当有一个泛型类实例时,您也可以使用GetType的旧的方式去调用一个实例。.

        SimpleGeneric<int> sgI = new SimpleGeneric<int>();

    Type alsoGT = sgI.GetType();

    讨论

    不能直接获取泛型类的类型,因为如果不提供一个类型参数,泛型类将没有类型(参考秘诀4.2获得更多信息)。只有通过类型参数实例化的泛型类才有Type

    如果您在使用typeof操作符时,只提供泛型类型定义而不提供类型参数,将得到下面的错误:

    // 这产生一个错误:

        // Error 26 Using the generic type 'CSharpRecipes.Generics.SimpleGeneric<T>'

        // requires '1' type arguments

        Type gt = typeof(SimpleGeneric);

    阅读参考

    查看秘诀4.2;参考MSDN文档中的“typeof”主题。

    4.4 使用相应的泛型版本替换ArrayList

    问题

    您希望通过将所有ArrayList对象替换为相应的泛型版本以提高应用程序的效率,并使得代码更易于使用。当结构体或其他值类型存储在这些数据结构中时,会导致装箱/拆箱操作,这时就需要这么做。

    解决方案

    使用更有效率的泛型类System.Collections.Generic.List来替换已存在的System.Collection.ArrayList类。

    下面是使用System.Collection.ArrayList对象的简单例子:

        public static void UseNonGenericArrayList()

        {

            // 创建一个ArrayList.

            ArrayList numbers = new ArrayList();

            numbers.Add(1); // 导致装箱操作

            numbers.Add(2); // 导致装箱操作

            // 显示ArrayList内的所有整数

            // 每次迭代都导致拆箱操作

            foreach (int i in numbers)

            {

                Console.WriteLine(i);

            }

            numbers.Clear();

    }

    相同的代码使用了System.Collections.Generic.List对象

        public static void UseGenericList()

        {

            // 创建一个List.

            List<int> numbers = new List<int>();

            numbers.Add(1);

            numbers.Add(2);

            // 显示List中的所有整数.

            foreach (int i in numbers)

            {

                Console.WriteLine(i);

            }

            numbers.Clear();

    }

    讨论

    因为所有的应用程序几乎都会使用ArrayList,从提升您的应用程序的执行效率开始是一个不错的选择。对于应用程序中简单使用ArrayList的地方来说,这种替代是非常容易的。但有些地方需要注意,例如,泛型List类未实现Icloneable接口而ArrayList实现了它。

    4-1显示了两个类中的等价成员。

    ArrayList类成员

    等价的泛型List类成员

    Capacity 属性

    Capacity属性

    Count属性

    Count属性

    IsFixedSize属性

    ((IList)myList).IsFixedSize

    IsReadOnly属性

    ((IList)myList).IsReadOnly

    IsSynchronized属性

    ((IList)myList).IsSynchronized

    Item属性

    Item属性

    SyncRoot属性

    ((IList)myList).SyncRoot

    Adapter 静态方法

    N/A

    Add 方法

    Add方法

    AddRange方法

    AddRange方法

    N/A

    AsReadOnly方法

    BinarySearch方法

    BinarySearch方法

    Clear方法

    Clear方法

    Clone方法

    Getrange(0, numbers.Count)

    Contains方法

    Contains方法

    N/A

    ConvertAll方法

    CopyTo方法

    CopyTo方法

    N/A

    Exists方法

    N/A

    Find方法

    N/A

    FindAll方法

    N/A

    FindIndex方法

    N/A

    FindLast方法

    N/A

    FindLastIndex方法

    N/A

    ForEach方法

    FixedSize 静态方法

    N/A

    Getrange方法

    Getrange方法

    IndexOf方法

    IndexOf方法

    Insert方法

    Insert方法

    InsertRange方法

    InsertRange方法

    LastIndexOf方法

    LastIndexOf方法

    ReadOnly 静态方法

    AsReadOnly方法

    Remove方法

    Remove方法

    N/A

    RemoveAll方法

    RemoveAt方法

    RemoveAt方法

    RemoveRange方法

    RemoveRange方法

    Repeat 静态方法

    使用for循环和Add方法

    Reverse方法

    Reverse方法

    SetRange方法

    InsertRange方法

    Sort方法

    Sort方法

    Synchronized 静态方法

    lock(myList.SyncRoot) {…}

    ToArray方法

    ToArray方法

    N/A

    trimExcess方法

    TRimToSize方法

    trimToSize方法

    N/A

    trueForAll方法

     

    4-1中的几个ArrayList的成员和泛型List的成员并非一一对应。从属性开始说,只有CapacityCountItem属性两个类中都存在。为了弥补List类中的几个缺失的属性,可以把它显式转换为Ilist接口。下面的代码演示了如何使用这些显式转换以获得缺失的属性。

    List<int> numbers = new List<int>();

        Console.WriteLine(((IList)numbers).IsReadOnly);

        Console.WriteLine(((IList)numbers).IsFixedSize);

        Console.WriteLine(((IList)numbers).IsSynchronized);

        Console.WriteLine(((IList)numbers).SyncRoot);

     

    注意,由于缺少返回同步版本的泛型List代码和缺少返回固定尺寸的泛型List代码,IsFixedSizeIsSynchronized属性将总是返回falseSyncRoot属性被调用时将总是返回相同的对象,本质上这个属性返回this指针。微软已经决定从所有泛型集合类中去除创建同步成员的功能。做为代替,他们推荐使用lock关键字去锁住整个集合或其他类型的同步对象来满足您的需要。

    静态的ArrayList.Repeat在泛型List中没有对应的方法。做为代替,您可以使用下面的泛型方法:

        public static void Repeat<T>(List<T> list, T obj, int count)

        {

            if (count < 0)

            {

                throw (new ArgumentException(

                        "参数count 必须大于或等于零"));

            }

            for (int index = 0; index < count; index++)

            {

                list.Add(obj);

            }

    }

    这个泛型方法有三个参数:

    list

    泛型List对象

    obj

    将被以指定次数添加进泛型List中的对象

    count

    obj添加进泛型类中的次数

    因为Clone方法也没有出现在泛型List类中(因为这个类并没有实现Icloneable接口),您可以使用泛型List类的GetRange方法做为替代。

        List<int> oldList = new List<int>();

        // 给oldList添加元素…

    List<int> newList = oldList.GetRange(0, oldList.Count);

    GetRange方法对List对象中一个范围的元素执行浅拷贝(跟ArrayList中的Clone方法接近)。在此例中这个范围是所有元素。

    提示:ArrayList默认的初始容量是16个元素,而List<T>的默认初始容量为4个元素。这意味着当添加第17个元素时,List<T>不得不改变尺寸(重新分配内存)3次,而ArrayList只重新分配一次。这一点在评估应用程序性能时需要被考虑。

  • 相关阅读:
    C#高级编程第11版
    做点字符串题
    Codeforces Round #681 (Div. 1, based on VK Cup 2019-2020
    Educational Codeforces Round 97 题解
    AtCoder Regular Contest 106 题解
    Kick Start Round G 2020 题解
    CCSP 2020题解
    Codeforces Round #675 (Div. 2) 题解
    AtCoder Regular Contest 104
    Kick Start Round F 2020 题解
  • 原文地址:https://www.cnblogs.com/kakaliush/p/2269811.html
Copyright © 2011-2022 走看看