当前位置: 首页 > news >正文

net 自定义泛型那点事

泛型概述

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。

泛型定义

泛型的定义主要有以下两种:
1.在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。(这是当今较常见的定义)
2.在程序编码中一些包含参数的类。其参数可以代表类或对象等等。(人们大多把这称作模板)不论使用哪个定义,泛型的参数在真正使用泛型时都必须作出指明。
一些 强类型编程语言支持泛型,其主要目的是加强 类型安全及减少类转换的次数,但一些支持泛型的编程语言只能达到部分目的。

 

正文

 加入我想输出double ,int 和 dateTime类型的类型名字和他们的值。现在需要定义方法如下

复制代码
using System;
using System.Data;

namespace testData
{
    class Program
    {
        static void Main(string[] args)
        {
            ShowInt(2);
            ShowDateTime(DateTime.Now);
            ShowDouble(2.52);
            Console.Read();
        }
        public static void ShowInt(int value)
        {
            Console.WriteLine($"typeName:{value.GetType().Name},Value:{value}");
        }
        public static void ShowDouble(double value)
        {
            Console.WriteLine($"typeName:{value.GetType().Name},Value:{value}");
        }
        public static void ShowDateTime(DateTime value)
        {
            Console.WriteLine($"typeName:{value.GetType().Name},Value:{value}");
        }
    }
}
复制代码

这样写起来,好像比较麻烦,我们可不可以用一个方法来代替呢???

我们很多初学者都接触过这两个泛型,

List<int> list = new List<int>();
Dictionary<int, string> dic = new Dictionary<int, string>();

第一个是列表,第二个我们称为字典,那么我们可不可以自己定义一个泛型方法呢????

泛型的语法结构及定义

泛型语法: 泛型类或方法的后面 “<T>” T 是占位符,可以是任意字母,主要代表一个类型,如果是方法,参数就应当为占位符参数。 如 Show<T>(T t);方法,User<T> 类   。

泛型的特点:1.延迟声明,2使用的时候在声明

1.泛型方法的定义和使用

复制代码
using System;
using System.Collections.Generic;
using System.Data;

namespace testData
{
    class Program
    {
        static void Main(string[] args)
        {
            Show<int>(1);
            Show<double>(1.904);
            Show<DateTime>(DateTime.Now);
            Show<string>("wbc");
            Console.Read();
        }
        public static void Show<T>(T t)
        {
            Console.WriteLine($"typeName:{t.GetType().Name},Value:{t}");
        }
    }
}
复制代码

我们会发现,完全可以运行,一个方法就搞定.那么我们可不可以省略 <int> ,答案是肯定的,当没有涉及到装箱拆箱操作的时候,我们完全可以省略,如下

复制代码
using System;
using System.Collections.Generic;
using System.Data;

namespace testData
{
    class Program
    {
        static void Main(string[] args)
        {
            Show(1);
            Show (1.904);
            Show(DateTime.Now);
            Show("wbc");
            User u = new User();
            Show(u);
            Console.Read();
        }
        public class User {

        }
        public static void Show<T>(T t)
        {
            Console.WriteLine($"typeName:{t.GetType().Name},Value:{t}");
        }
    }
}
复制代码

 有人会说了,我使用Object 作为参数,一样可以实现,为什么不使用object呢,一切类型的父类是object ,应当可以的啊??,答案是肯定的,也是可以的,知所以不使用,是因为使用object类型的时候,会产生装箱拆箱操作,这个操作会损失精度。

 

2泛型类的定义和使用

泛型类的语法和泛型方法的语法很像,只是关键字是class ,如 Public Class MyGer<T>{

}

那么我们来看下泛型类的使用,看如下案列:

复制代码
using System;
using System.Collections.Generic;
using System.Data;

namespace testData
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person()
            {
                Name="zhangsan",Age=28,Id=1,Id_No="110000198212193145",Address="beijiang",Sex="女"
            };
            MyGrenric<Person> gren = new MyGrenric<Person>();
            gren.Show(p);
            Console.Read();
        }
      
        
    }
    /// <summary>
    /// 人的父类
    /// </summary>
    public class BasePopleModel {

        public string  Name { get; set; }
        public int Age { get; set; }

        public string Address { get; set; }

        public string Id_No { get; set; }

        public string Sex { get; set; }
    }
    public class Pople {
        public string Name { get; set; }
        public int Age { get; set; }

        public string Address { get; set; }

        public string Id_No { get; set; }

        public string Sex { get; set; }
        public override string ToString()
        {
            string result = "{"+$"name:{this.Name},age : {this.Age},sex : {this.Sex},no : {this.Id_No} "+"}";
            return base.ToString();
        }
    }
    //人的信息
    public class Person : BasePopleModel {

        public int Id { get; set; }

        public override string ToString()
        {
            string result = "{ "+ $"name : {base.Name},age : {base.Age},sex : {base.Sex},no : {base.Id_No} , id : {this.Id}"+" }";
            return result;
        }
    }
    public class MyGrenric<T>
    {
        public void Show(T t) {
             Console.WriteLine(t);
        }
    }
}
复制代码

 看了上面的代码,我们可以看出,泛型类里面的方法,可以是普通方法和泛型方法,当普通方法使用泛型的时候,我们可以省略泛型,上诉代码替换为:

 public void Show<T>(T t) {
             Console.WriteLine(t);
        }
是一样的结果。但是泛型类也有一个弊端,那就是失去了继承类的继承性质,如

BasePopleModel p = new Person()
{
Name="zhangsan",Age=28,Id=1,Id_No="110000198212193145",Address="beijiang",Sex="女"
};
MyGrenric<Person> gren = new MyGrenric<Person>();
gren.Show(p);

这个时候,我们的代码就会报错。那如何在泛型中保留类的基础性,使用如下语法就能做到:

  View Code

当我们所有继承了BasePopleModel的子类,都可以使用这个泛型类。

 

3泛型接口的定义和使用

我们来看下代码,定义一个泛型接口,和定义泛型类的语法结构是一样的,他本身也具有接口的特性。代码如下:

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
  public interface  IBaseImpl<T>
    {
         int State { get; set; }

        void Show(T t);
        void Search<S>(S s,T t);
    }
}
复制代码

 

当我们普通类继承这个泛型接口的时候,我们会发现,继承不了,生成编译项目的时候,会提示出错误信息:如下图

那我们来试试,泛型类来继承泛型接口,看好使不好使,把我们上面创建的泛型类继承我们的接口(MyGrenric<T>:IBaseImpl<T>)如下:

复制代码
 public class MyGrenric<T>:IBaseImpl<T>
    {
        public int State { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

        public void Search<S>(S s, T t)
        {
            throw new NotImplementedException();
        }

        public void Show(T t) {
             Console.WriteLine(t);
        }
    }
复制代码

 

我们发现是能运行的.

现在问题来了,刚才我们的实例类继承泛型接口继承不了,我们的实例类继承泛型类能继承吗??,有没有什么办法,让我们的实例类继承我们的泛型接口和泛型类呢?我们先来看看,能不能实例类继承泛型类

我们会发现还是继承不了:既然前边说了,T只是一个占位符,我们可不可以显示的写出一个类呢??

我们发现,这样是可以的,没有编译错误,那么我泛型类和泛型接口的占位符都是T,那么我们使用不同 的类可以吗??,答案是否定的,绝对不可以,一个占位符只能代表一个类型,所以我们要使用不同的类型,就需要使用不同的占位符,如:

 

泛型约束

 前边学习了这么多自定义泛型的知识,我们基本就把整个泛型学习完了,我们之前一直都是说T,S,是泛型的一个占位符,可以是任意类型,那我们可以限定这个类型吗?答案是肯定的,继续看图片

通过上诉,我们能看出,我们限定了类型,只能是Pople 类类型。限定语法,“只有在泛型类和接口之后跟WHERE 泛型占位符 :类型”。

where T: 类型值说明限定规范
class限定泛型只能是class 类型可以有参数构造函数或无参数构造函数,不能和其他关键字一起使用
struct限定泛型只能是struct类型不可以和其他类型一起使用
new()限定只能是类类型,切有无参数构造函数必须有参数构造函数,不能和其他关键字一起使用
类类型如果传入的是父类,则保留继承性质
值类型

这里就不过多演示上述内容,我们在这里只演示class ,代码如下

 

复制代码
using System;
using System.Collections.Generic;
using System.Data;

namespace testData
{
    class Program
    {
        static void Main(string[] args)
        {
            BasePopleModel p = new Person()
            {
                Name="zhangsan",Age=28,Id=1,Id_No="110000198212193145",Address="beijiang",Sex="女"
            };
            MyGrenric<BasePopleModel> gren = new MyGrenric<BasePopleModel>();
            gren.Show(p);
            Console.Read();
        }
    }
    /// <summary>
    /// 人的父类
    /// </summary>
    public class BasePopleModel
    {

        public string  Name { get; set; }
        public int Age { get; set; }

        public string Address { get; set; }

        public string Id_No { get; set; }

        public string Sex { get; set; }
    }
    public class Pople {
        public string Name { get; set; }
        public int Age { get; set; }

        public string Address { get; set; }

        public string Id_No { get; set; }

        public string Sex { get; set; }
        public override string ToString()
        {
            string result = "{"+$"name:{this.Name},age : {this.Age},sex : {this.Sex},no : {this.Id_No} "+"}";
            return base.ToString();
        }
    }
    //人的信息
    public class Person: BasePopleModel   {

        public Person() {

        }
        public int Id { get; set; }


        public void Show(BasePopleModel s)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            string result = "{ "+ $"name : {base.Name},age : {base.Age},sex : {base.Sex},no : {base.Id_No} , id : {this.Id}"+" }";
            return result;
        }
    }
    public class MyGrenric<T> where T :  class ,new()
    {
       
        public void Show(T t) {
             Console.WriteLine(t);
        }
    }
 
    //public interface IBaseImpl<S> where S : class
    //{
    //    int State { get; set; }

    //    void Show(S s);
    //}

}
复制代码

 

总结:泛型类必须继承在泛型类上,如果作为普通类的父类,必须显示指定其类型,在约束的时候,泛型类不能指定值类型的约束。

泛型接口必须被泛型类和泛型接口继承,如果被普通接口和普通类继承,必须显示的指定类型,必须放在多个继承文件的最后。在约束的时候,不能使用new()。

本文只是介绍常用的泛型使用方向,很多其他方向没有详细介绍,常用就是泛型类的使用,并不怎么涉及到泛型的继承,如果一个项目涉及到泛型继承,证明这个项目也是快重构了。不过在开发过程中,泛型的约束是经常使用的。仅供参考

 

姓名:王柏成 英文名:WbcSky QQ:1477865775 电子邮件:w329357255@126.com

相关文章:

  • Android Studio 解决 Error: /data/local/tmp/com.mazaiting.imgtomp4test安装失败问题
  • CSS选择器:伪类(图文详解)
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • 我的Java设计模式-中介者模式
  • debian配置node和nodejs环境
  • iOS开发CoreData的多表关联
  • [xsy2369]取名字
  • c3p0和druid性能测试过程中sybase卡死的问题解决过程记录
  • Alamofire上传文件
  • django第一个app,3
  • 坦克大战1.0版
  • 【Html5】-- 塔台管制
  • 国内域名国内服务器,不备案解决80端口不开放方法
  • python
  • Java与Unix时间戳的相互转换
  • [译]前端离线指南(上)
  • eclipse的离线汉化
  • express + mock 让前后台并行开发
  • JavaScript类型识别
  • laravel 用artisan创建自己的模板
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • SpringCloud集成分布式事务LCN (一)
  • VUE es6技巧写法(持续更新中~~~)
  • Vue小说阅读器(仿追书神器)
  • windows-nginx-https-本地配置
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 经典排序算法及其 Java 实现
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 坑!为什么View.startAnimation不起作用?
  • 收藏好这篇,别再只说“数据劫持”了
  • 用Canvas画一棵二叉树
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​虚拟化系列介绍(十)
  • #Lua:Lua调用C++生成的DLL库
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)Linux——Linux常用指令
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (三)终结任务
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (正则)提取页面里的img标签
  • (转载)Google Chrome调试JS
  • .htaccess配置常用技巧
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • /bin/bash^M: bad interpreter: No such file or directory
  • @Controller和@RestController的区别?
  • @WebService和@WebMethod注解的用法
  • @取消转义
  • @在php中起什么作用?
  • [20171102]视图v$session中process字段含义
  • [Android Pro] listView和GridView的item设置的高度和宽度不起作用
  • [AX]AX2012 AIF(四):文档服务应用实例