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

简介: 先说些题外话,只所以写这些东西。是看了CSDN上的曹版主的一篇:手把手教编程,不知道有没有人愿意参与。说实话,我工作四年,总感觉晕晕乎乎的,好多技术都 懂,但是没有一项是精通的。看了这篇帖子,说实在话我可想去,去聆听大神的教导。

   先说些题外话,只所以写这些东西。是看了CSDN上的曹版主的一篇:手把手教编程,不知道有没有人愿意参与。说实话,我工作四年,总感觉晕晕乎乎的,好多技术都

懂,但是没有一项是精通的。看了这篇帖子,说实在话我可想去,去聆听大神的教导。主要是想提高自己,由于没有时间,又因为身在北京。所以就没有报名(呵呵,报名也

可能没有机会去)。所以自己就去图书馆去搞他提出的这些概念。其实我更希望在北京的大神们也能组织类似的活动。我想响应一定也很多,其实我想如果能组织一次这样的

活动,大神们也会得到提高的。这些都是我在图书馆看书的所得,分享给大家,同时也请管理员同志手下留情,不要每一篇都给打入冷宫,我已经很用心去做了。另外对这

感兴趣的童鞋们可以加我的QQ348537081,我们可以讨论一下心得。最后喜欢看书的童鞋也可以联系我,每周六首都图书馆,风雨无阻。

  说的有些多,下面转入正题。其实这篇文章是泛型介绍(接上一篇,具体的事例随后呈上)的扩展与修改。

因为家中无法联网,我都是提前用wps提前写好的,所有格式上可能会有一些问题,所以请大家多担待。

2.2接口约束(where Tinterface-name

  为了规定某个数据类型必须实现某个接口,需要声明一个接口约束(interface constraint).有了这种约束之后,甚至不需要执行类型转换,就可以调用一个显示的接口成员实现.

口约束的主要功能与基类约束完全一样。首先,它允许开发人员在泛型类中使用接口的成员。其次,它确保只能使用实现了特定接口的类型实参。这意味着对于任何给定的接

口约束,类型实参要么是接口本身,要么实现了接口的类。

注:可以通过使用逗号分隔的列表来同时指定多个接口。如果某个约束同时包含基类和接口,则先指定基类再指定接口列表。


如:为了确保T类型参数都是先了IComparable接口,


public class Binary<T> where T:System.IComparable{...}


编译器会确保每次使用Binary类的时候,都必须指定一个实现了IComparable接口的类型参数.

 

  下面的程序通过改写前一个程序中的电话列表程序来说明接口约束的用途。在此程序中,PhoneNumber类被转换为一个名为IPhoneNumber的接口。然后,FriendSupplier实现了该接口。

  

class NotFoundException1 : Exception
    {
        public NotFoundException1() : base() { }

        public NotFoundException1(string str) : base(str) { }

        public NotFoundException1(string str, Exception inner) : base(str, inner) { }

        protected NotFoundException1(System.Runtime.Serialization.SerializationInfo si,
            System.Runtime.Serialization.StreamingContext sc)
            : base(si, sc) { }
    }

    public interface IPhoneNumber
    {
        public string Number { get; set; }

        public string Name { get; set; }
    }

    public class Friend1 : IPhoneNumber
    {
        public string Number { get; set; }

        public string Name { get; set; }

        public bool IsWorkNumber { get; set; }

        public Friend1(string name, string num, bool wk)
        {
            Name = name;
            Number = num;
            IsWorkNumber = wk;
        }
    }

    public class Supplier1 : IPhoneNumber
    {
        public string Name { get; set; }

        public string Number { get; set; }

        public Supplier1(string name, string num)
        {
            this.Name = name;
            this.Number = num;
        }
    }

    class FriendEmail1 { }

    class PhoneList1<T> where T : IPhoneNumber
    {
        T[] phList;
        int end;

        public PhoneList1()
        {
            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)
        {
            foreach (T item in phList)
            {
                if (item.Name == name)
                    return item;
            }

            throw new NotFoundException1();
        }

        public T FindByNum(string num)
        {
            foreach (T item in phList)
            {
                if (item.Number == num)
                    return item;
            }

            throw new NotFoundException1();
        }


 

 

 

2.3 struct/class 约束(where T:class/struct)

    另一个重要的泛型约束是将类型参数限制为一个值类型或者一个引用类型.编译器不允许在一个约束中将System.ValueType指定成基类.相反,C#提供了特殊的语法,这种语法同时适用于引用类型.在这种语法中,不是为T指定一个基类.相反,只需要指定关键字struct或者class.在同时存在其他约束时,class或者struct必须位于约束列表的开头

:

Public struct Nullable<T>:IFormattable,IComparable,IComparable<Nullable<T>>,INullable where T:struct

{//.......}

2.4 new()构造函数约束

  New()构造函数约束允许开发人员实例化一个泛型类型的对象。一般情况下,无法创建一个泛型类型参数的实例。然而,new()约束改变了这种情况,它要求类型实参必须

提供一个无参数的构造函数。在使用new()约束的时候,可以通过调用该无参构造函数来创建对象。

class myclass

        {

            public myclass() { }

        }

        class Test<T> where T : new() 

        {

            T obj;

            public Test() 

            {

                obj = new T();

            }

        }

 

调用:

 Test<myclass> x = new Test<myclass>();

注意:myclass 不必显示地声明一个无参数构造函数,默认的构造函数也可以满足这种约束。然而,如果某个类除了无参的构造函数外还需要定义其他的构造函数,那么必须

为该类显式地声明不含参数的构造函数。

使用new()时,应注意三点:

一、它可以和其他约束一起使用,但必须位于约束列表的末端。

二、New()不允许给类型参数的构造函数传递实参

三、不可以同时使用new()约束和值类型约束

 

2.5多重约束

  同一个参数可以使用多个约束。这种情况下,需要使用一个逗号分隔的约束列表.在该列表中,第一个约束必须是class或者struct(如果存在的话),或者基类(如果被指

定)。指定class或者struct的同时也指定基类约束是非法的。接下来是接口约束。最后是new ()约束。如:

Class Gen<T> where T:myClass,IMyInterface,new(){}

如果有多个类型参数,那么每个类型名称的前面都要使用一个where关键字.如:

Class Gen<T,V> where T:class

Where T:struct

{//.....}

2.6.泛型方法


为了定义泛型方法,需要紧接在方法名之后添加类型参数语法,


public T method<T>(T params)
{
return params;
}
泛型方法也允许指定约束:


public T method<T>(T params)
where TIComparable
{
return params;
}

2.7.Default关键字:


  要确定用于创建泛型类实例的类型,需要了解一个最基本的情况:他们是引用类型还是值类型.若不知道这个情况,就不能用下面的代码赋予null:

public class myGenericClass<T1,T2,T3>
{
    T1 t1;
    public myGenericClass()
{
    t1=null;
}
}


如果T1是值类型,t1不能是null,所以这段代码将不会编译.幸好,我们可以用default关键字的新用法解决了它.
public myGenericClass()
{
  t1=default(T1);
}


其结果是:如果t1是引用类型,就给它赋予null,如果它是值类型,就赋予默认值.如数字类型,这个默认值就是0.

几个泛型类型的示例:


2.8定义泛型结构


public struct myStruct<T1,T2>
{
  public T1 item1;
  public T2 item2;

}


2.9定义泛型接口
  interface myInterfacee<T>{}


2.10 .定义泛型方法


 public T GetDefault<T>()
{

  return default(T);

}


2.11定义泛型委托


  public delegate T1 myDelegate<T1,T2>(T2 op1,T2 op2) where T1:T2

 

  结束语:泛型到这了,下一次介绍下反射,关于前几篇C#我会抽时间重新写的,能让他更详细点,其实这次C#基础知识的复习让我学到很多东西,以前模糊的概念,

现在变得非常清晰了。我曾经面试过好多人,有工作三年,有两年,甚至工作经验比我还长的。对这些基础性的知识都知之甚少,当然也包括我自己。因为如果没

有这些概念,工作中也不会可虑到这些东西,当然也就谈不上引用。所以我们都只能做底层程序。程序猿想提高,重新学这些基础知识吧,真的……

 

目录
相关文章
|
Shell 开发工具 git
git拉取分支的方法?
1.在工作空间下,右键,选择Git Bash 进入到里面
371 0
|
域名解析 存储 Java
一步步教你搭建自己的云服务器
一步步教你搭建自己的云服务器
|
并行计算 TensorFlow 算法框架/工具
tensorflow安装
tensorflow安装——GPU版
405 2
|
运维 开发者 Docker
Docker容器化技术在运维中的应用实践
【8月更文挑战第27天】本文旨在探讨Docker容器化技术如何在现代运维工作中发挥核心作用,通过深入浅出的方式介绍Docker的基本概念、优势以及实际应用场景。文章将结合具体案例,展示如何利用Docker简化部署流程、提高资源利用率和加强应用的可移植性。读者将获得对Docker容器技术在实际运维中应用的全面认识,并能够理解其在提升运维效率与质量方面的重要性。
|
缓存 NoSQL 网络安全
【Azure Redis 缓存】 Python连接Azure Redis, 使用redis.ConnectionPool 出现 "ConnectionResetError: [Errno 104] Connection reset by peer"
【Azure Redis 缓存】 Python连接Azure Redis, 使用redis.ConnectionPool 出现 "ConnectionResetError: [Errno 104] Connection reset by peer"
310 0
|
消息中间件 Linux 测试技术
【xenomai3内核解析】系列文章大纲
该博客系列详细解析了Linux实时操作系统框架Xenomai,包括实时操作系统的概念、Linux为何非实时、嵌入式实时Linux方案等。内容涵盖Xenomai内核构建、组件结构、源码介绍、实时性测试及接口应用。此外,深入探讨了双核基石IPipe、系统调用、时间子系统、任务管理、同步与互斥、内存管理、信号处理、实时IPC、POSIX IPC、实时驱动模型RTDM、Rtnet、用户态实时库libcobalt和实时性能优化等方面。适合对Linux实时系统感兴趣的读者学习研究。
499 0
【xenomai3内核解析】系列文章大纲
|
Java 关系型数据库 MySQL
实时计算 Flink版产品使用合集之通过scan.incremental.snapshot.chunk.key-column参数配置来处理无主键表的全量同步,增量数据进不来的原因是什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
SQL 消息中间件 分布式计算
大数据-143 - ClickHouse 集群 SQL 超详细实践记录!(一)
大数据-143 - ClickHouse 集群 SQL 超详细实践记录!(一)
489 0
|
存储 安全 网络安全
POP3 协议在计算机网络中的优缺点
【8月更文挑战第19天】
607 0
POP3 协议在计算机网络中的优缺点
|
Python
如何使用Python的Requests库进行网络请求和抓取网页数据?
【4月更文挑战第19天】使用Python Requests库进行网络请求和网页数据抓取:安装库,导入requests,发送GET/POST请求,检查状态码(如`status_code==200`表示成功),解析响应内容(如`response.text`),处理Cookies和请求头,以及用try-except捕获异常。更多功能可深入学习Requests库。
493 2