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);

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

 

当我们所有继承了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()。

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

原文地址:https://www.cnblogs.com/cjm123/p/8271311.html

时间: 2024-08-07 02:35:07

net 自定义泛型那点事的相关文章

通过反射创建自定义泛型的实例。

比如有这样一个泛型:Demo.GenericsSimple<T,TT> 我想要通过反射创建一个Demo.GenericsSimple<string,int>的实例可以通过下面的格式进行创建: System.Reflection.Assembly.GetExecutingAssembly().CreateInstance("命名空间.User`形参数量N[[1形参类型全名,形参类型所在的程 序集名称],[2形参类型全名,形参类型所在的程序集名称],[3形参类型全名,形参类型

.NET基础之自定义泛型

在.NET中泛型使用非常频繁,在控制台应用程序中,默认的引入了System.Collection.Generics名称空间,其中就提供了我们经常使用的泛型:List<T>和Dictionary<T>,相信用过它们的都知道它们的强大.还有一种我们经常使用的简单的泛型:System.Nullable<T>,即可空类型.我们可以: System.Nullable<int> nullableInt; 声明一个可空的int类型,由于C#语法对这个做了简化通常我们都不这

泛型和自定义泛型

1.自定义泛型 public static <T>T getFactor(T t){}  注意T是所在的地方 public <T>void reverse(T[] arr){}     没有返回值类型的情况 T Type  类型      E  Element    元素

java JDK8 学习笔记——第18章 自定义泛型、枚举与注释

第十八章 自定义泛型.枚举与注释 18.1 自定义泛型 泛型定义: (1)仅定义在方法上的泛型语法 (2)用来限制泛型可用类型的extends与super关键字(3)?类型通配字符的使用 18.1.1 使用extends与? 1.若extends之后指定了类与接口,想再指定其他接口,可以使用&连接. 2.如果B是A的子类,而Node< B>可视为一种Node< A>,则称Node具有共变性或有弹性的.Java泛型不具有共变性,可以使用类型通配字符?与extends来声明变量

JAVA基础_自定义泛型

泛型的来源 在Java中,泛型借鉴了C++的模版函数,从而引入了泛型. C++泛型 int add(int x,int y){ return x + y; } float add(float x.float y){ return x + y; } double add(double x,double y){ return x + y; } // 泛型函数对上面的整数,浮点数的抽象和实现 template<class T> T add(T x,T y){ return x + y; } 自定义泛

52.在方法上面自定义泛型

自定义泛型:自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量 方法上自定义泛型:    修饰符  <声明自定义的泛型>返回值类型 函数名(使用自定义泛型){        //代码块    } 例如:    public <T>String func(T t){        } 在泛型中不能使用基本数据类型,如果使用基本数据类型,那么就使用基本数据类型对应的的包装类 byte    Byteshort     Shortint      Integerlong   Lo

关于自定义Dialog的那些事

Dialog也就是传说中的弹出框,系统自带的一些布局和功能比较简单,一般来说满足不了开发的需求,因此,需要我们自己动手,来实现一个自定义的Dialog. 首先,如果要实现一个自己的Dialog,我们需要继承自Dialog.Dialog的构造函数一共有三种格式,我们至少需要生命其中的一种形式,才能够使用. 构造函数的格式如下: 1.public MyCameraDialog(Context context, boolean cancelable, OnCancelListener cancelLi

自定义泛型

泛型的目的:还是代码重用.T:一般叫做“类型参数”,把数据类型作为参数传递.一般用T类表示或者以大写T开头的比如:TKey,TValue.TOutput.TResult…泛型,在.net2.0版本才开始引入.泛型类.泛型接口.泛型方法.泛型委托(*)where T1 : struct //约束T1必须是值类型 where T : class, new()//约束T必须是引用类型 where TC : new() //这个类型必须带有一个无参数的构造函数[要求:1.构造函数不能为私有,2.类型不能

自定义泛型_无多态_通配符无泛型数组_jdk7泛型使用

通配符 T, K, V, E 等泛型字母为有类型, 类型参数赋予具体的值 ? 未知类型 类型参数赋予不确定值, 任意类型 只能用在 声明类型上,方法参数上, 不能用在定义泛型类上 上限 extends, 指定类型必须是继承某个子类. 或者实现某个接口 (不是用 implements), 即 <= 如 ? extends Fruit ? extends List 不能添加信息 存在以下规则, 如 List<Fruit> 满足 List<? extends Fruit> List