看到他我一下子就悟了-- 泛型(1)

1.泛型概念:       本质上,术语”泛型”指的是”参数化类型(parameterized types)”.参数化类型非常重要,因为它们可以在创建类.结构.方法和委托的时候将要操作的数据类型作为参

数进行指定.使用参数化类型的类.结构.方法和委托都可以称为泛型,如”泛型类”或者”泛型方法”.

       在具体声明一个变量或者实例化之前,类型参数T只是一个占位符。等到具体声明和实例化的时候,编译器要求代码指定类型参数。泛型类型声明了泛型参数占位符类型,由泛型类型的用户填写这些占位符,并作为泛型的参数提供给泛型类型.

2.泛型约束:约束声明了泛型要求的类型参数的特征。

    为了声明一个约束,需要使用where关键字,后跟一对”参数:要求”.其中,”参数”必须是泛型类型中定义的一个参数,而”要求”用于限制类型从

中”派生”的类或接口,或者限制必须存在一个默认构造器,或者限制使用一个引用/值类型约束.

2.1基类约束(where T:base-class-name)

有的时候,你可能需要限制类型从一个特定的类派生.这是用基类约束(base class constraint)做到的.使用基类约束,可以指定某个类型实参

必须继承的基类.基类约束有两个重要功能.

  首先,他允许在泛型类中使用由约束指定的基类所定义的成员.例如,可以调用基类的方法或者使用基类的属性.如果没有基类约束,编译器就无法知道某

个类型实参拥有哪些成员.通过提供基类约束,编译器将知道所有的类型实参都拥有由指定的基类所定义的成员.

  基类约束的第二个功能是,确保只适用支持指定基类的类型实参.这意味着对于任意给定的基类约束,类型实参要么是基类本身,要么是派生于该基

类.如果试图使用没有匹配或者继承指定的类型实参,就会导致编译错误 例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//泛型:基类约束
//基类约束两个作用:1.基类约束允许泛型类访问基类的成员
//                 2.确保只能使用满足该约束的类型参数,从而实现类型安全 
namespace generic
{
    /*案例描述:假设要创建一个管理电话号码列表的工具.另外,假定不同组的用户
     使用的是不同的列表.例如,一个列表用于朋友,令外一个列表用于供应商等.
     */
    /// <summary>
    /// PhoneNumber基类,它用于存储姓名和姓名相对应的电话号码
    /// </summary>
    class PhoneNumber
    {
        public string Number { get; set; }
        public string Name { get; set; }
        public PhoneNumber(string n, string num)
        {
            this.Name = n;
            this.Number = num;
        }
    }
    /// <summary>
    /// 朋友电话
    /// </summary>
    class Friend : PhoneNumber
    {
        /// <summary>
        /// 电话号码是否为工作号码
        /// </summary>
        public bool IsWorkNumber { get; private set; }
        public Friend(string n, string num, bool wk)
            : base(n, num)
        {
            this.IsWorkNumber = wk;
        }
    }
    /// <summary>
    /// 供应商电话
    /// </summary>
    class Supplier : PhoneNumber
    {
        public Supplier(string n, string num)
            : base(n, num)
        {
        }
    }
/*为了管理电话列表,下面创建一个名为PhoneList的类.由于希望该类能够
 * 管理任意类型的电话列表,因此将其实现为泛型.另外,由于列表管理的一部分内容是
 * 根据姓名查询号码,或者根据号码查询姓名,因此要给它添加约束,从而
 * 确保存储在列表中的对象的类型必须是PhoneNumber派生类的实例
 */
    /// <summary>
    /// 管理任意类型的电话列表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class PhoneList<T> where T:PhoneNumber
    {
        T[] phList;
        int end;
        public PhoneList()
        {
            phList = new T[10];
            end = 0;
        }
        public bool Add(T newEntry)
        {
            if (end == 10) return false;
            phList[end] = newEntry;
            end++;
            return true;
        }
        public T FindByName(string name)
        {
            for (int i = 0; i < end; i++)
            {
                if (phList[i].Name == name)
                    return phList[i];
            }
            throw new NotFoundException();
        }
        public T FindByNumber(string number)
        {
            for (int i = 0; i < end; i++)
            {
                if (phList[i].Number == number)
                    return phList[i];
            }
            throw new NotFoundException();
        }
    }
    /// <summary>
    /// 此类没有继承PhoneNumber,因此不能用于创建PhoneList
    /// </summary>
    class EmailFriend 
    {
    //.....
    }
    /*
     * 这是一个定制异常,虽然该示例只使用默认构造函数,但是出于说明的
     * 目的,NotFoundException实现了Exception定义的所有构造函数
     * 注意:这些构造函数只调用了Exception定义的相等基类构造函数.
     * NotFoundException没有向Exception添加任何内容,因此不需要
     * 执行任何进一步的操作
     */ 
    class NotFoundException : Exception
    {
        public NotFoundException():base(){}
        public NotFoundException(string str):base( str){}
        public NotFoundException(string str, Exception inner) :
            base(str, inner) { }
        protected NotFoundException(
            System.Runtime.Serialization.SerializationInfo si,
            System.Runtime.Serialization.StreamingContext se) :
            base(si, se) { }
    }
}

怎样调用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace generic
{
    class Program
    {
        static void Main(string[] args)
        {
            BaseClassConstraint();
            Console.Read();
        }

        //基类约束
        public static void BaseClassConstraint()
        {
           //可以通过编译
            PhoneList<Friend> plist = new PhoneList<Friend>();
            //错误添加
            //plist.Add(new Friend() {Name="Tom",Number="555-1234",IsWorkNumber=true });
        //正确添加
            plist.Add(new Friend("Tom", "5555-333", true));
            plist.Add(new Friend("Gary", "5555-332", true));
            plist.Add(new Friend("WangC", "5555-331", false));


            try
            {
                Friend frnd = plist.FindByName("Gary");
                Console.WriteLine(frnd.Name+":"+frnd.Number);

                if(frnd.IsWorkNumber)
                    Console.WriteLine("(work)");
                else
                    Console.WriteLine();
            }
            catch (NotFoundException)
            {
                Console.WriteLine("Not Found");
            }

            //供应商
            PhoneList<Supplier> plist2 = new PhoneList<Supplier>();
            plist2.Add(new Supplier("Global Hardware", "400-123"));
            plist2.Add(new Supplier("Computer", "400-124"));
            plist2.Add(new Supplier("NetWorkCity", "400-125"));

            try
            {
                Supplier sp = plist2.FindByNumber("400-124");
                Console.WriteLine(sp.Name+":"+sp.Number);
            }
            catch (NotFoundException)
            {
                Console.WriteLine("Not Found");
            }

            //没有继承的
           // PhoneList<EmailFriend> plist3 = new PhoneList<EmailFriend>();
        }
    }
   
}

 未完待续……

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一枝花算不算浪漫

[读书笔记]C#学习笔记五: C#3.0自动属性,匿名属性及扩展方法

357100
来自专栏菜鸟前端工程师

JavaScript学习笔记023-对象方法0包装对象0静态属性

10620
来自专栏趣谈编程

Unicode与UTF-8的区别

要弄清Unicode与UTF-8的关系,我们还得从他们的来源说起,下来我们从刚开始的编码说起,直到Unicode的出现,我们就会感觉到他们之间的关系

13920
来自专栏Java3y

给女朋友讲解什么是Optional【JDK 8特性】

前两天带女朋友去图书馆了,随手就给她来了一本《与孩子一起学编程》的书,于是今天就给女朋友讲解一下什么是Optional类。

7530
来自专栏Kiba518

C#语法——泛型的多种应用

泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性、类型安全性和效率。

9730
来自专栏陈仁松博客

C# 7.0 探索之旅

模式匹配(Pattern matching) C# 7.0 引入了模式匹配的概念,一种从抽象的角度来说,指可以测试一个值是否有某种特定的“形状”、并在满足这一条...

48290
来自专栏大内老A

从yield关键字看IEnumerable和Collection的区别

C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的。相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”...

22770
来自专栏技术博客

C#基础知识系列一(goto、i++、三元运算符、ref和out、String和string、重载运算符)

  这两天在网上看到的总结很多,尤其是博客园中的,很多很多,也给了我很多的启发,当然自己也总结过,而且有很多人也给与我一些意见和看法。不管怎样,自己还是先把所谓...

12820
来自专栏Ryan Miao

Java8学习(3)- Lambda 表达式

猪脚:以下内容参考《Java 8 in Action》 本次学习内容: Lambda 基本模式 环绕执行模式 函数式接口,类型推断 方法引用 Lambda 复...

34090
来自专栏函数式编程语言及工具

Scalaz(24)- 泛函数据结构: Tree-数据游览及维护

上节我们讨论了Zipper-串形不可变集合(immutable sequential collection)游标,在串形集合中左右游走及元素维护操作。这篇我...

19860

扫码关注云+社区

领取腾讯云代金券