zoukankan      html  css  js  c++  java
  • 用泛型实现参数化类型

    泛型将大量安全检查从执行时转移到了编译时进行,泛型实现了类型和方法的参数化。

    为什么需要泛型
    • 将额外的信息作为方法或类型声明的一部分加以说明
    • IDE能基于额外的信息向程序员提供智能感知
    • 方法调用者对自己传递的值和方法返回值更有把握
    • 维护代码时,可以更好的掌握代码思路
    日常使用的简单泛型
    泛型字典
    static Dictionary<string, int> CountWords(string text)
    {
    Dictionary<string, int> frequencies;
    frequencies = new Dictionary<string, int>();//创建从单词到频率的新映射
    string[] words = Regex.Split(text, @"w+");//将文本分解为单词
    foreach (string word in words)//添加或更新映射
    {
    if (frequencies.ContainsKey(word))
    {
    frequencies[word]++;
    }
    else
    {
    frequencies[word] = 1;
    }
    }
    return frequencies;
     
    }
    #region 3—1,统计文本单词数
    string text = @"Do you like greem eggs and Ham? I do not like them, Sam-i-AM";
    Dictionary<string, int> frequencies = CountWords(text);
    foreach (KeyValuePair<string, int> entry in frequencies)//打印映射中的每个键/值对
    {
    string word = entry.Key;
    int frequency = entry.Value;
    Console.WriteLine("{0}:{1}", word, frequency);
    }
    #endregion
    泛型类型和类型参数
    泛型两种形式:泛型类型(类,接口,委托,结构)和泛型方法
    类型参数是真实类型的占位符。Dictionary<TKey, TValue>//TKey, TValue类型参数。 Dictionary<string, int>//string,int类型实参
    没有为泛型类型参数提供类型实参,那么就是一个未绑定泛型类型
    如果指定了类型实参,就是一个已构造类型。已构造类型可以是开发或封闭的,开放类型还包括一个类型参数,封闭类型每个部分都是明确的
    可以认为封闭类型拥有开放类型的API。
    泛型方法和判读泛型声明
    static double TakeSquareRoot(int x)//平方根3-2返回
    {
    return Math.Sqrt(x);
    }
    #region 3-2List<T>.ConcertAll<TOutput>
    List<int> integer = new List<int>();//创建并填充整个列表
    integer.Add(1);
    integer.Add(2);
    integer.Add(3);
    integer.Add(4);
    Converter<int, double> converter = TakeSquareRoot;//创建委托
    List<double> doubles;
    doubles = integer.ConvertAll<double>(converter);//调用泛型方法来转换列表
    foreach (double d in doubles)
    {
    Console.WriteLine(d);
    }
    #endregion
    在非泛型方法中实现泛型方法
    static List<T> MakeList<T>(T first, T second)
    {
    List<T> list = new List<T>();
    list.Add(first);
    list.Add(second);
    return list;
    }
    List<string> list = MakeList<string>("Line 1", "Line 2");
    List<string> list1 = MakeList("Line 1", "Line 2");//类型推断:只适用于泛型方法,不适用于泛型类型
    Console.WriteLine(list.Capacity);
    foreach (string i in list)
    {
    Console.WriteLine(i);
    }
    深化与提高
    类型约束
    类型参数可以被指定为任意类型时,它们未被约束
    引用类型约束
    确保使用的类型实参是引用类型。类型实参任何类,接口,委托,或已知是引用类型的另一个类型参数。
    struct TefSample1<T> where T : class//引用类型约束,使用这种方式约束一个类型实参后,可以用==和!=来比较引用(包括NULL)
    {
     
    }
    值类型约束
    确保使用的类型实参是值类型,包括枚举,但是将可空类型排除在外
    class TefSample<T> where T : struct//值类型约束,使用这种方式约束一个类型实参后,不可以用==和!=来比较
    {
     
    }
    构造函数类型约束
    必须是所有类型参数的最后一个约束,它检查是否有一个可用创建类型实例的无参构造函数。所有值类型都有一个默认的无参构造函数,而且显示声明的构造函数和无参构造函数是用相同的语法来调用的。
    public static T CreateUbstance<T>() where T : new()//检查类型实例是否有一个可用于创建类型实例的构造函数
    {
    return new T();
    }
    T为int和object都是有效的,但T为string是无效的,因为string没有一个无参构造函数
    转换类型约束
    可以规定一个类型实参必须可以转换成另一个类型实参
    class Sample<T> where T : Stream//转换类型约束
    {
     
    }
    Sample<Stream> s = new Sample<Stream>();
    组合约束
    class Sqmple<T, U>
    where T : class
    where U : struct,T//组合约束,每一个值类型都有一个构造函数,假如已经有了一个值类型约束,就不允许在有构造函数约束
    {
     
    }
    //指定多个接口,但只能指定一个类
    class Sample2<T> where T : Stream, IEnumerable<string>, IComparable<int>
    {
     
    }
    泛型方法类型实参的类型推断
    类型推断只适用于泛型方法,不适用于泛型类型
    实现泛型
    默认值表达式
    //3-4将一个值与类型默认值比较
    static int CompaerToDefault<T>(T value) where T : IComparable<T>
    {
    return value.CompareTo(default(T));
    }
    #region 3-4以一个泛型方式将一个给定的值和一个默认值比较
    Console.WriteLine(CompaerToDefault("x"));
    Console.WriteLine(CompaerToDefault(10));
    Console.WriteLine(CompaerToDefault(0));
    Console.WriteLine(CompaerToDefault(-10));
    Console.WriteLine(CompaerToDefault(DateTime.MinValue));
    #endregion
    直接比较
    static bool AreReferencesEqual<T>(T first, T second) where T : class
    {
    return first == second;
    }
    #region 3-5 用==和!=进行引用比较
    string name = "Jon";
    string intro1 = "My name is" + name;
    string intro2 = "My name is" + name;
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));
    #endregion
    对==进行重载,AreReferenxesEqual使用object
    表示一对值
    #region 表示一对值的泛型类
    public sealed class Pair<T1, T2> : IEquatable<Pair<T1, T2>>
    {
    //每个封闭类型都有它自己的静态集
    private static readonly IEqualityComparer<T1> FirstComparer = EqualityComparer<T1>.Default;
    private static readonly IEqualityComparer<T2> SecondComparer = EqualityComparer<T2>.Default;
     
    private readonly T1 first;
    private readonly T2 second;
     
    public Pair(T1 first, T2 second)
    {
    this.first = first;
    this.second = second;
    }
     
    public T1 First { get { return first; } }
     
    public T2 Second { get { return second; } }
     
    public bool Equals(Pair<T1, T2> other)
    {
    return other != null && FirstComparer.Equals(this.First, other.First) && SecondComparer.Equals(this.Second, other.Second);
    }
     
    public override bool Equals(object obj)//重写
    {
    return base.Equals(obj as Pair<T1, T2>);
    }
     
    public override int GetHashCode()
    {
    return FirstComparer.GetHashCode(first) * 37 + SecondComparer.GetHashCode(second);
    }
     
    }
    #endregion
    #region 使用泛型方法的非泛型类型进行推断
    public static class Pair
    {
    public static Pair<T1, T2> Of<T1, T2>(T1 first, T2 second)
    {
    return new Pair<T1, T2>(first, second);
    }
    }
    #endregion
    #region 表示一对值的泛型类
    Pair<int, string> pair = new Pair<int, string>(10, "value");
    #endregion
     
    #region 使用泛型方法的非泛型类型进行推断
    Pair<int, string> pair1 = Pair.Of(10, "VALUE");//类型推断根据方法进行,对于每一个方法实参,都尝试推断泛型方法的一些实参(简单推断技术),对于泛型方法要么推断要么全部显示指定。
     
    #endregion
    高级泛型
    静态字段和静态构造函数
    每个封闭的类型都有它自己的静态字段集
    #region 3-8 证明不通的封闭类型具有不同的静态字段
    //每个封闭类型有一个静态字段
    TypeWithField<int>.field = "First";
    TypeWithField<string>.field = "Secind";
    TypeWithField<DateTime>.field = "Third";
     
    TypeWithField<int>.PrinfField();
    TypeWithField<string>.PrinfField();
    TypeWithField<DateTime>.PrinfField();
    #endregion
    class TypeWithField<T>
    {
    public static string field;
    public static void PrinfField()
    {
    Console.WriteLine(field + ":" + typeof(T).Name);
    }
    }
    一个泛型类型可能嵌套在另一个泛型类型中,而且一个类型可能有多个泛型参数。
    #region 3-9 嵌套泛型类型的静态构造函数
    Outer<int> o = Outer.Of<int>();
     
    Outer<int>.Inner<String, DateTime>.DummyMethod();
    Outer<string>.Inner<int, int>.DummyMethod();
    Outer<object>.Inner<string, object>.DummyMethod();
    Outer<string>.Inner<string, object>.DummyMethod();
    Outer<object>.Inner<object, string>.DummyMethod();
    Outer<int>.Inner<string, DateTime>.DummyMethod();//任何封闭类型的构造函数只执行一次
     
    #endregion
    public class Outer<T>
    {
    public class Inner<U, V>
    {
    static Inner()
    {
    Console.WriteLine("Outer<{0}>.Inner<{1},{2}>",
    typeof(T).Name,
    typeof(U).Name,
    typeof(V).Name);
    }
    public static void DummyMethod() { }
    }
    }
    JIT编译器如果处理泛型
    JIT为每个以值类型作为类型实参的封闭类型都创建不同的代码,所有使用引用类型作为类型实参的封闭类型都共享本地代码(所有引用都具有相同的大小。32位CLR上是4字节,64位CLR上是8字节)栈上一个引用所需空间始终相同。
    ArrayList中,需要对每个字节进行装箱。
    在32位CLR上:
    ArrayList:8字节对象开销,4字节(1字节)数据本身,引用4字节
    Liat<byte>:2字节(数据实际1字节)
    泛型迭代
    使用foreach,需要将集合的类型实参作为迭代变量类型使用
    #region 3-10
    class CountingEnumerable : IEnumerable<int>
    {
    public IEnumerator<int> GetEnumerator()//隐式实现IEnumerable<T>
    {
    return new CountingEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()//显示实现IEnumerable
    {
    return GetEnumerator();
    }
     
    }
     
    class CountingEnumerator : IEnumerator<int>
    {
    int current = -1;
     
    public bool MoveNext() //接口IEnumerator的实现,将枚举数推进到集合的下一个元素。
    {
    current++;
    return current < 10;
    }
     
    public int Current { get { return current; } }//隐式实现IEnumerator<T>.Current
     
    object IEnumerator.Current { get { return Current; } }//显示实现IEnumerator.Current
     
    public void Reset() //接口IEnumerator的实现,将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
    {
    current = -1;
    }
     
    public void Dispose() { }//接口IDisposable,执行与释放或重置非托管资源相关的应用程序定义的任务。
    }
    #endregion
    #region 3-10 一个完整的泛型枚举
    CountingEnumerable counter = new CountingEnumerable();
    foreach (int x in counter)//foreach会自动负责Dispose调用事项,用于结束迭代时释放资源
    {
    Console.WriteLine(x);
    }
    #endregion
    反射和泛型
    1.对泛型使用typeof
    typeof可以通过两种方式作用于泛型类型——获取泛型定义和获取特定的构造函数
    #region 3-11对类型参数使用tupeof操作符
    DemonstrateTypeof<int>();
    #endregion
    #region 3-11
    static void DemonstrateTypeof<X>()
    {
    Console.WriteLine(typeof(X));//显示方法的类型参数
     
    Console.WriteLine(typeof(List<>));//显示泛型类型
    Console.WriteLine(typeof(Dictionary<,>));
     
    Console.WriteLine(typeof(List<X>));//显示封闭类型(使用了类型参数)
    Console.WriteLine(typeof(Dictionary<string, X>));
     
    Console.WriteLine(typeof(List<long>));//显示封闭类型
    Console.WriteLine(typeof(Dictionary<long, Guid>));
     
    Console.WriteLine(typeof(Pair<,>));
    Console.WriteLine(typeof(TypeWithField<>));
    }
    #endregion
    在IL中,类型参数的数量是在框架所用的完整类型名称中指定的,在完整类型名称之后,会添加一个‘,然后是参数数量。
    2.System。Type的属性和方法
    任何特定的类型中有一个Type对象
    #region 获取泛型和以构造Type对象的各种方式
    string listTypeName = "System.Collections.Generic.List`1";//System.Collections.Generic.List`1
     
    Type defByName = Type.GetType(listTypeName);
     
    Type closedByName = Type.GetType(listTypeName + "[System.String]");//将类型实参放入方括号中
    Type closeByMethod = defByName.MakeGenericType(typeof(string));
    Type closedByTypeof = typeof(List<string>);
     
    Console.WriteLine(closeByMethod == closedByName);
    Console.WriteLine(closedByName == closedByTypeof);
     
    Type defByTypeof = typeof(List<>);
    Type defByMethod = closedByName.GetGenericTypeDefinition();
     
    Console.WriteLine(defByMethod == defByName);
    Console.WriteLine(defByName == defByTypeof);
    #endregion
    返回4次true
  • 相关阅读:
    大端与小端编号方法的区别
    socket、listen 等函数的打电话隐喻
    windows 网络编程报错 error LNK2019
    有符号数与无符号数之间的转换
    C++ 代码命名建议
    编写启发式代码的方法
    求给定数目的前 n 个素数
    不使用 “+” 实现加法操作
    二叉搜索树中两个节点的旋转
    Python玩转硬件:TPYBoard-Micropython开发板大盘点
  • 原文地址:https://www.cnblogs.com/Tan-sir/p/5169200.html
Copyright © 2011-2022 走看看