C#【进阶】泛型

news2024/11/12 17:06:39

1、泛型

在这里插入图片描述

文章目录

    • 1、泛型
      • 1、泛型是什么
      • 2、泛型分类
      • 3、泛型类和接口
      • 4、泛型方法
      • 5、泛型的作用
          • 思考 泛型方法判断类型
    • 2、泛型约束
      • 1、什么是泛型
      • 2、各泛型约束
      • 3、约束的组合使用
      • 4、多个泛型有约束
          • 思考1 泛型实现单例模式
          • 思考2 ArrayList泛型实现增删查改

1、泛型是什么

泛型实现了类型参数化,达到代码重用目的
通过类型参数化来实现同一份代码上操作多种类型
    
泛型相当于类型占位符
定义类或方法时使用替代符代表变量类型
当真正使用类或方法时再具体指定类型

2、泛型分类

泛型类和泛型接口
	基本语法
    class 类名<泛型占位字母>
    interface 接口名<泛型占位字母>

泛型函数
    基本语法
    函数名<类型占位字母>(参数列表)
//泛型占位字母可以有多个,用逗号分开

3、泛型类和接口

TestClass<int> t = new TestClass<int>();
t.value = 1;

TestClass<string> t2 = new TestClass<string>();
t2.value = "ok";

TestClass2<int, string, float, bool> t3 = new TestClass2<int, string, float, bool>();
class TestClass<T>
{
    public T value;
}
class TestClass2<T, M, L,Key>
{
    public T Value;
    public M GetM;
    public L GetL;
    public Key GetKey;
}
interface TestInsterface<T>
{
    T vale
    {
        get;
        set;
    }
}
class Test : TestInsterface<int>
{
    public int vale { get; set ;}
}

4、泛型方法

1、普通类中的泛型方法
    Test2 test2 = new Test2();
    test2.Fun<string>("ok");

    class Test2
    {
        public void Fun<T>(T val)
        {
            Console.WriteLine(val);
        }

        public void Fun<T>()
        {
            //用泛型类型,做一些逻辑处理
            T t = default(T);
        }

        public T Fun<T>(string test)
        {
            return default(T);
        }

        public void Fun<T,K,M>(T t, K k, M m){}
    }

2、泛型类中的泛型方法
    Test2<int> test3 = new Test2<int>();
    test3.Fun(1.2f);
    test3.Fun(true);
    test3.Fun(10);

    class Test2<T>
    {
        public T value;
        //这个不是泛型方法,因为T是泛型类声明的时候就指定类型了
        public void Fun(T t)
        {

        }
        public void Fun<T>(T t) { }
    }

5、泛型的作用

1、不同类型对象的相同逻辑处理就可以使用泛型
2、使用泛型可以一定程度避免装箱拆箱
例如:优化ArrayList
class ArrayList<T>
{
    private T[] array;

    public void Add(T value)
    {

    }
    public void Remove(T value)
    {

    }
}
思考 泛型方法判断类型
//定义一个泛型方法,方法内判断该类型为何类型,并返回类型的名称与占有的字节数
//如果是int,则返回整形,4字节
//只考虑int,char,float,string,如果是其他类型,则返回其他类型
//可以通过typeof(类型) == typeof(类型)的方式进行类型判断
Console.WriteLine(Fun<int>());
Console.WriteLine(Fun<char>());
Console.WriteLine(Fun<float>());
Console.WriteLine(Fun<string>());
Console.WriteLine(Fun<bool>());
Console.WriteLine(Fun<uint>());

string Fun<T>()
{
    if (typeof(T) == typeof(int))
    {
        return string.Format("{0},{1}字节","整形",sizeof(int));
    }
    else if (typeof(T) == typeof(char))
    {
        return string.Format("{0},{1}字节", "字符", sizeof(char));
    }
    else if (typeof(T) == typeof(float))
    {
        return string.Format("{0},{1}字节", "单精度浮点数", sizeof(float));
    }
    else if (typeof(T) == typeof(string))
    {
        return  "字符串";
    }
    return "其他类型";
}

2、泛型约束

1、什么是泛型

让泛型的类型有一定的限制 where
	1、值类型	 			where 泛型字母:stuct
	2、引用类型				where 泛型字母:class
	3、存在无参公共构造函数	where 泛型字母:new()
	4、某个类本身或其派生类	where 泛型字母:类名
	5、某个接口的派生类型		where 泛型字母:接口名
	6、另一个泛型类型本身或者派生类	where 泛型字母a:泛型字母b   

2、各泛型约束

1、值类型	
    Test1<int> test1 = new Test1<int>();
    test1.TestFun(1.2f);
    class Test1<T> where T : struct
    {
        public T value;
        public void TestFun<K>(K k) where K : struct
        {

        }
    }
2、引用类型
    Test2<Random> t2 = new Test2<Random>();
    t2.value = new Random();
    t2.TestFun(new Object());
    class Test2<T> where T : class
    {
        public T value;
        public void TestFun<K>(K k) where K : class { }
    }
3、存在无参公共构造函数
    Test3<Test1> t3 = new Test3<Test1>();
    Test3<Test2> t4 = new Test3<Test2>();//必须是具有公共的无参构造函数的非抽象类型
    class Test3<T> where T : new()
    {
        public T value;
        public void TestFun<K>(K k) where K : new() { }
    }
    class Test1 { }
    class Test2 
    {
        public Test2(int i) { }
    }
4、类约束
    Test4<Test1> t4 = new Test4<Test1>();
    Test4<Test2> t5 = new Test4<Test2>();

    class Test4<T> where T : Test1
    {
        public T value;
        public void TestFun<K>(K k) where K : Test1 { }
    }
    class Test1 { }
    class Test2 : Test1
    {
        public Test2(int i) { }
    }
5、接口约束
    Test5<IFoo> t6 = new Test5<IFoo>();
    Test5<Test1> t5 = new Test5<Test1>();
    class Test5<T> where T : IFoo
    {
        public T value;
        public void TestFun<K>(K k) where K : IFoo { }
    }
    interface IFoo { }
    class Test1 : IFoo{ }
6、另一个泛型约束
    Test5<Test1,IFoo> t6 = new Test5<Test1,IFoo>();
    Test5<Test1, Test1> t7 = new Test5<Test1, Test1>();
    class Test5<T,U> where T : U
    {
        public T value;
        public void TestFun<K,V>(K k) where K : V { }
    }
    interface IFoo { }
    class Test1 : IFoo { }

3、约束的组合使用

class Test7<T> where T : class,new(){}

4、多个泛型有约束

class Test8<T,K> where T:class,new() where K:struct{}
思考1 泛型实现单例模式
//用泛型实现一个单例模式基类

Test.Instance.value = 2;
GameMgr.Instance.value = 3;
class SingleBase<T> where T : new()
{
    private static T instance = new T();
    public static T Instance
    {
        get
        {
            return instance;
        }
    }
}
class GameMgr : SingleBase<GameMgr>
{
    public int value = 10;

}
class Test
{
    private static Test instance = new Test();
    public int value = 10;
    private Test() { } 
    public static Test Instance {  get { return instance;} }
}
思考2 ArrayList泛型实现增删查改
//利用泛型知识点,仿造ArrayList实现一个不确定数组类型的类
//实现增删查改方法
ArrayList<int> array = new ArrayList<int>();
Console.WriteLine(array.Count);
Console.WriteLine(array.Capacity);
array.Add(1);
array.Add(2);
array.Add(4);
Console.WriteLine(array.Count);
Console.WriteLine(array.Capacity);

Console.WriteLine(array[1]);
Console.WriteLine(array[3]);

array.Remove(2);
Console.WriteLine(array.Count);
for (int i = 0; i < array.Count; i++)
{
    Console.WriteLine(array[i]);
}

array[0] = 88;
Console.WriteLine(array[0]);
ArrayList<string> array2 = new ArrayList<string>();

class ArrayList<T>
{
    private T[] array;
    //当前存了多少数
    private int count;
    public ArrayList()
    {
        count = 0;
        //开始容量为16
        array = new T[16];
    }
    public void Add(T value)
    {
        //是否要扩容
        if (count >= Capacity)
        {
            //每次扩容两倍
            T[] newArray = new T[Capacity * 2];
            for (int i = 0; i < Capacity; i++)
            {
                newArray[i] = array[i];
            }
            //重写指向地址
            array = newArray;
        }
        //不需要扩容
        array[count++] = value;
    }
    public void Remove(T value)
    {
        int index = -1;
        //遍历存的值,而不是数组的容量
        for (int i = 0; i < Count; i++)
        {
            if (array[i].Equals(value))
            {
                index = i;
                break;
            }
        }
        if (index != -1)
        {
            RemoveAt(index);
        }
    }
    public void RemoveAt(int index)
    {
        if (index < 0 || index >= Count)
        {
            Console.WriteLine("索引不合法");
            return;
        }
        //删除后,将空出来的位置前移
        for (; index < Count - 1; index++)
        {
            array[index] = array[index + 1];
        }
        //把最后剩下的位置设为默认值
        array[Count - 1] = default(T);
        count--;
    }
    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= Count)
            {
                Console.WriteLine("索引不合法");
                return default(T);
            }
            return array[index];
        }
        set
        {
            if (index < 0 || index >= Count)
            {
                Console.WriteLine("索引不合法");
                return;
            }
            array[index] = value;
        }
    }
    /// <summary>
    /// 获取容量
    /// </summary>
    public int Capacity
    {
        get
        {
            return array.Length;
        }
    }
    /// <summary>
    /// 得到具体存了多少值
    /// </summary>
    public int Count
    {
        get
        {
            return count;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1666666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Autoxjs 实践-Spring Boot 集成 WebSocket

概述 最近弄了福袋工具&#xff0c;由于工具运行中&#xff0c;不好查看福袋结果&#xff0c;所以我想将福袋工具运行数据返回到后台&#xff0c;做数据统计、之后工具会越来越多&#xff0c;就弄了个后台&#xff0c;方便管理。 实现效果 WebSocket&#xff1f; websocket是…

【JavaEE初阶系列】——Cookie和Session应用之实现登录页面

目录 &#x1f6a9;本章目标 1.登录页面 2.servlet处理上述的登录请求 3.网站主页(成功登录之后的页面&#xff09; &#x1f6a9;实现过程 &#x1f393;登录页面 &#x1f393;Servlet处理登录请求 &#x1f388;获取请求传来的参数(用户名和密码) &#x1f388;验证…

Electron学习笔记(五)

文章目录 相关笔记笔记说明 七、系统1、系统对话框2、自定义窗口菜单3、系统右键菜单4、快捷键(1)、监听网页按键事件 &#xff08;窗口需处于激活状态&#xff09;(2)、监听全局按键事件 &#xff08;窗口无需处于激活状态&#xff09;(3)、补充&#xff1a;自定义窗口菜单快捷…

Three.js基础练习——渲染一个立方体

1.学习内容参考了 three.js入门教程--零基础也能学会_threejs菜鸟教程-CSDN博客 本章内容包含渲染立方体&#xff0c;并配合ui工具食用~ 2.效果图 import * as THREE from three import * as dat from dat.gui import { OrbitControls } from three/addons/controls/OrbitC…

【网站项目】SpringBoot803房屋租赁管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【Golang】VSCode进行GO的调试

原来的launch.json {"version": "0.2.0","configurations": [{"name": "Golang","type": "go","request": "launch","program": "${workspaceFolder}","…

Linux技术---部署PXE服务器实现批量安装操作系统

部署PXE服务器实现批量安装操作系统 部署PXE服务器实现批量安装操作系统 部署PXE服务器实现批量安装操作系统1.安装相关服务组件1.1 安装tftp和xinetd1.2 安装DHCP服务1.3 准备 Linux 内核、初始化镜像文件、 PXE 引导程序、安装FTP服务并准备安装源1.4 配置启动菜单文件1.5 验…

JVM之运行时数据区

Java虚拟机在运行时管理的内存区域被称为运行时数据区。 程序计数器&#xff1a; 也叫pc寄存器&#xff0c;每个线程会通过程序计数器记录当前要执行的字节码指令的地址。程序计数器在运行时是不会发生内存溢出的&#xff0c;因为每个线程只存储一个固定长度的内存地址。 JAVA虚…

[蓝桥杯 2021 国 ABC] 123(java)——前缀和,思维

目录 题目 解析 代码 这么久了&#xff0c;我终于能不看别人代码完整写出来了&#xff0c;呜呜呜。虽然过程也是很曲折。 题目 解析 这个题&#xff0c;找其中数列的规律&#xff0c;1,1,2,1,2,3,1,2,3,4&#xff0c;...&#xff0c;因此我们把拆分成行列&#xff0c;如下…

Qt---信号和槽

一、信号和槽机制 所谓信号槽&#xff0c;实际就是观察者模式。当某个事件发生之后&#xff0c;比如&#xff0c;按钮检测到自己被点击了一下&#xff0c;它就会发出一个信号&#xff08;signal&#xff09;。这种发出是没有目的的&#xff0c;类似广播。如果有对象对这个信号…

车载测试和传统测试有什么区别

搞清楚车载测试和传统应用测试的区别,就可以大胆冲冲冲! 车载测试随着市场的需求量增加又火来一波,一直’遥遥领先’的我们一定要告诉大家一个事实:车载测试和传统的应用测试是有很大区别的. 测试对象不一样 传统测试:测试的对象无非就是各种应用,比如电脑端的web系统(使用浏…

Git系列:git tag 使用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

FANUC机器人坐标系的分类和简介

1、概述 坐标系是为了确定机器人的位置和姿势而在机器人或空间上定义的位置指标系统&#xff0c;坐标系分为关节坐标系和直角坐标系&#xff0c;直角坐标系遵循右手定则&#xff0c;而关节坐标系则是以机器人每个轴所转动的角度来表示机器人当前的位置。 2、坐标系的分类及简…

weblogic 反序列化 CVE-2018-2628

这个漏洞因为java版本问题一直下载不了ysoserial反序列化工具&#xff0c;没办法生成payload。这里记录一下漏洞原理。 一、漏洞简介 Weblogic Server中的RMI 通信使用T3协议在Weblogic Server和其它Java程序&#xff08;客户端或者其它Weblogic Server实例&#xff09;之间传…

团结引擎+OpenHarmony 3 通信

团结引擎和鸿蒙之间通信 因为 ts 并没有像 JAVA 有反射的调用&#xff0c;所以我们必须要像 Web GL 平台一样通过导出的行为告诉引擎到底哪些 ts 的接口可以给 C# 来调用。 1 在 Tuanjie 引擎里 需要一个tsllib文件&#xff0c;用于设置给导出对象 C#使用。就可以直接创建以 …

Unity基础

概述 基础知识 3D教学 数学计算公共类Mathf 练习: 三角函数 练习&#xff1a; Unity中的坐标系 Vector3向量 向量模长和单位向量 向量加减乘除 练习&#xff1a; 向量点乘 向量叉乘 向量插值运算 Quaternion四元数 为何要使用四元数 四元数是什么 四元数常用方法 四元数计算 练…

GeoServer安装以及部署

GeoServer介绍 GeoServer是一个开源的服务器软件&#xff0c;用于共享和编辑地理空间数据。它支持多种地理空间数据格式&#xff0c;并且可以发布为多种服务格式&#xff0c;如Web Feature Service (WFS)、Web Map Service (WMS)、Web Coverage Service (WCS)&#xff0c;以及…

十二、Redis主从复制

与其他的中间件存在同样的问题&#xff0c;在单机的情况&#xff0c;随着业务的增长&#xff0c;会面临着灾备、性能方面的压力。Redis在这方面提供了一主一从、一主多从的结构。这种结构同时也是实现读写分离功能的基础。即主节点提供写能力&#xff0c;从节点提供读能力。为了…

【C/C++】C/C++ 车票售票系统设计与实现(源码+课件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

初识C语言——第十八天

循环while/do while while 语法结构 while(表达式) 循环语句; break:在while循环中&#xff0c;break用于永久的终止循环 continue:在while循环中&#xff0c;continue的作用是跳过本次循环continue后面的代码 直接去判断部分&#xff0c;看是否进行下一次循环。 注意事项…