C#学习第15天:泛型

news2025/4/18 21:43:19

什么是泛型?


  • 定义:泛型允许您在类、接口和方法中定义占位符,这些占位符在使用时可以指定为具体的类型。
  • 作用:通过减少重复代码和提供更强的类型检查,提高了代码的可重用性和性能。

泛型的核心概念 


1.泛型类

  • 泛型类能够操作特定的数据类型,而不需要为每种数据类型写一个类。提高代码复用性。
using System;
using System.Collections.Generic;

public class GenericContainer<T>
{
    private T item;
    
    // 设置泛型项的值
    public void SetItem(T value) 
    {
        item = value;
    }
    
    // 获取泛型项的值
    public T GetItem()
    {
        return item;
    }
}

使用泛型类示例:

    public static void Demo()
    {
        // 使用int类型
        var intContainer = new GenericContainer<int>();
        intContainer.SetItem(10);
        
        // 使用string类型
        var stringContainer = new GenericContainer<string>();
        stringContainer.SetItem("Hello");
    }

2.泛型方法

可以在非泛型类中定义泛型方法,允许该方法独立于其所在类的参数类型。

public class GenericMethods
{
    // ref关键字表示参数按引用传递
    public void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    // 演示多个类型参数的泛型方法
    public TResult Convert<TInput, TResult>(TInput input) where TResult : new()
    {
        // 处理类型转换逻辑
        return new TResult();
    }
}

使用泛型方法的示例:

    public static void Demo()
    {
        var methods = new GenericMethods();
        
        // 演示Swap方法
        int x = 10, y = 20;
        Console.WriteLine($"交换前: x = {x}, y = {y}");
        methods.Swap(ref x, ref y);
        Console.WriteLine($"交换后: x = {x}, y = {y}");

        string str1 = "Hello", str2 = "World";
        Console.WriteLine($"交换前: str1 = {str1}, str2 = {str2}");
        methods.Swap(ref str1, ref str2);
        Console.WriteLine($"交换后: str1 = {str1}, str2 = {str2}");

        // 演示Convert方法
        int number = 42;
        string result = methods.Convert<int, string>(number);
        Console.WriteLine($"转换结果: {result}");
    }

 3.泛型接口

允许接口的方法和属性使用泛型类型参数。

public interface IRepository<T>
{
    void Add(T item);
    void Remove(T item);
    T GetById(int id);
    IEnumerable<T> GetAll();
}

使用示例:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// 实现用户仓储类
public class UserRepository : IRepository<User>
{
    private List<User> users = new List<User>();

    public void Add(User item)
    {
        users.Add(item);
    }

    public void Remove(User item)
    {
        users.Remove(item);
    }

    public User GetById(int id)
    {
        return users.FirstOrDefault(u => u.Id == id);
    }

    public IEnumerable<User> GetAll()
    {
        return users;
    }
}

    // 演示仓储接口的使用
public static void Demo()
{
    var userRepo = new UserRepository();
        
    // 添加用户
    userRepo.Add(new User { Id = 1, Name = "张三" });
    userRepo.Add(new User { Id = 2, Name = "李四" });
        
    // 获取所有用户
    var allUsers = userRepo.GetAll();
    foreach (var user in allUsers)
    {
       Console.WriteLine($"用户ID: {user.Id}, 名称: {user.Name}");
    }
        
    // 根据ID获取用户
    var user1 = userRepo.GetById(1);
    Console.WriteLine($"查找到用户: {user1?.Name}");
        
     // 删除用户
    userRepo.Remove(user1);
}

高级主题


约束

限制泛型参数的类型以增加灵活性和安全性。

  • where T : struct:T必须是值类型。
  • where T : class:T必须是引用类型。
  • where T : new():T必须有一个无参构造函数。
  • where T : BaseClass:T必须继承自BaseClass。
  • where T : InterfaceName:T必须实现某接口。
public class Example<T> where T : new()
{
    public T CreateInstance()
    {
        return new T();
    }
}

public class GenericConstraints
{
    public T Sum<T>(T a, T b) where T : struct 
}

 泛型委托

泛型不仅适用于类和方法,还可以用于委托。

public delegate T Transformer<T>(T arg);

class Program
{
    static int Square(int x) => x * x;

    static void Main()
    {
        Transformer<int> transformer = Square;
        Console.WriteLine(transformer(3)); // 输出:9
    }
}

使用场景


1.集合类

  • List<T>, Dictionary<TKey,TValue>, Queue<T>等都是泛型类的例子,可存储任何类型数据。

2.算法实现

  • 可以创建通用的排序、搜索或其他算法,适用于任何类型。

3.类型安全事件处理

  • 泛型委托用于事件系统中,确保类型匹配并提高安全性。

实践习题 


1.创建一个泛型栈类GenericStack<T>,实现基本的栈操作:Push、Pop和Peek。

using System;
using System.Collections.Generic;

public class GenericStack<T>
{
    private List<T> elements = new List<T>();
    // 将元素添加到栈顶的Push操作
    public void Push(T item)
    {
        elements.Add(item);
    }
    // 移除并返回栈顶元素的Pop操作
    public T Pop()
    {
        if (elements.Count == 0)
        {
            throw new InvalidOperationException("The stack is empty.");
        }
        T item = elements[^1]; // ^1 是C# 8.0语法,用于访问最后一个元素
        elements.RemoveAt(elements.Count - 1);
        return item;
    }
    // 返回栈顶元素但不移除的Peek操作
    public T Peek()
    {
        if (elements.Count == 0)
        {
            throw new InvalidOperationException("The stack is empty.");
        }
        return elements[^1];
    }
}

public class Program
{
    public static void Main()
    {
        GenericStack<int> stack = new GenericStack<int>();
        stack.Push(10);
        stack.Push(20);
        stack.Push(30);

        Console.WriteLine(stack.Peek()); // 输出:30
        Console.WriteLine(stack.Pop());  // 输出:30
        Console.WriteLine(stack.Pop());  // 输出:20
    }
}

2.编写一个泛型类LimitedType<T>,仅允许实现了IDisposable接口的类型作为参数,并包含一个释放资源的方法。

using System;

public class LimitedType<T> where T : IDisposable, new()
{
    private T resource;

    public LimitedType()
    {
        resource = new T();
    }

    public void UseResource()
    {
        Console.WriteLine($"Using resource of type {typeof(T).Name}");
        // 假装使用资源
    }

    public void ReleaseResource()
    {
        Console.WriteLine($"Releasing resource of type {typeof(T).Name}");
        resource.Dispose();
    }
}

public class MyResource : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("MyResource disposed");
    }
}

public class Program
{
    public static void Main()
    {
        LimitedType<MyResource> limitedResource = new LimitedType<MyResource>();
        limitedResource.UseResource();
        limitedResource.ReleaseResource();
    }
}

说明:

  • LimitedType类使用where T : IDisposable, new()约束,这意味着T必须实现IDisposable接口,并且具有无参构造函数。
  • UseResource模拟使用资源,而ReleaseResource负责正确地释放资源。
  • MyResource类实现了IDisposable接口,用于演示如何正确地处置资源。

通过这些例子,我们展示了如何利用泛型提高代码的通用性和灵活性。如果有任何问题或需要进一步讲解,请随时告诉我!
 

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

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

相关文章

RestSharp和Newtonsoft.Json结合发送和解析http

1.下载RestSharp和Newtonsoft.Json 2编写ApiRequest和ApiResponse和调用工具类HttpRestClient 请求模型 /// <summary>/// 请求模型/// </summary>public class ApiRequest{/// <summary>/// 请求地址/api路由地址/// </summary>public string Route {…

【Pytorch之一】--torch.stack()方法详解

torch.stack方法详解 pytorch官网注释 Parameters tensors&#xff1a;张量序列&#xff0c;也就是要进行stack操作的对象们&#xff0c;可以有很多个张量。 dim&#xff1a;按照dim的方式对这些张量进行stack操作&#xff0c;也就是你要按照哪种堆叠方式对张量进行堆叠。dim的…

数据中台(大数据平台)之数据资源目录

数据资源目录是数据管理的账本&#xff0c;是数据应用的基础&#xff0c;更是是数据治理成果的体现&#xff0c;因此数据中台产品应提供数据资源目录编制、发布、资源挂载、下架的管理能力。 1.数据资源目录分类 资源目录能够支持基于业务特点创建和维护基础目录分类和特色目…

【随身WiFi】随身WiFi Debian系统优化教程

0.操作前必看 本教程基于Debian系统进行优化&#xff0c;有些操作对随身WiFi来说可能会带来负优化&#xff0c;根据需要选择。 所有操作需要在root用户环境下运行&#xff0c;否则都要加sudo 随身wifi Debian系统&#xff0c;可以去某安的随声WiFi模块自行搜索刷机 点赞&am…

JAVA Web_定义Servlet2_学生登录验证Servlet

题目 页面StudentLogin.html中有一HTML的表单代码如下&#xff1a; <form action"studentLogin" method"post">学生姓名&#xff1a;<input type"text" name"stuName" value""><br>登录密码&#xff1a;…

Unity入门笔记(缘更)

内容来源SiKi学院的Luna’s Fantasy 文章目录 一、基础知识1.准备2.基础知识1.层级(Layer)2.轴心点3.预制体(Prefab)4.刚体组件(Rigidbody)5.碰撞器组件(BoxCollider) 二、代码1.移动 一、基础知识 1.准备 Unity安装&#xff1a; https://unity.cn 2.基础知识 1.层级(Layer…

【Python】用Python写一个俄罗斯方块玩玩

【Python】用Python写一个俄罗斯方块玩玩 一、引言1.成品效果展示 二、思考准备1.思考设计2.代码设计2.1 游戏页面2.2 控件设计2.2.1 方块生成2.2.2 方块碰撞2.2.3 方块消融2.2.4 游戏主循环2.2.5 游戏窗口 三、游戏完整版 一、引言 今日看到侄子在玩游戏&#xff0c;凑近一看…

记录一次生产中mysql主备延迟问题处理

登录库&#xff1a; mysql -uXXXX -pXXXX -P3306 -hXXXXXX -A 备库上执行&#xff1a;show slave status\G 查看 seconds_Behind_Master&#xff0c;延迟 2705s&#xff0c;而且还一直在增加。 SHOW CREATE TABLE proc_i_income_temp; -- 查看表的结构 show index from proc…

ffmpeg无损转格式的命令行

将ffmpeg.exe拖入命令行窗口 c:\users\zhangsan>D:\ffmpeg-2025-03-11\bin\ffmpeg.exe -i happy.mp4 -c:v copy -c:a copy 格式转换后.mkv -c:v copy 仅做拷贝视频,不重新编码 -c:a copy 仅做拷贝音频 ,不重新编码

强化学习算法系列(五):最主流的算法框架——Actor-Critic算法框架

强化学习算法 &#xff08;一&#xff09;动态规划方法——策略迭代算法(PI)和值迭代算法(VI) &#xff08;二&#xff09;Model-Free类方法——蒙特卡洛算法(MC)和时序差分算法(TD) &#xff08;三&#xff09;基于动作值的算法——Sarsa算法与Q-Learning算法 &#xff08;四…

设计模式(结构型)-桥接模式

目录 摘要 定义 类图 角色 具体实现 优缺点 优点 缺点 使用场景 使用案例 JDBC 和桥接模式 总结 摘要 在软件开发领域&#xff0c;随着系统规模和复杂性的不断攀升&#xff0c;如何设计出具有良好扩展性、灵活性以及可维护性的软件架构成为关键挑战。桥接模式作为一…

【MySQL】MySQL数据库 —— 简单认识

目录 1. 数据库的介绍 1.1 什么是数据库 1.2 数据库和数据结构之间关系 2. 数据库分类 2.1 关系型数据库&#xff08;RDBMS&#xff09; 2.2 非关系型数据库 2.3 区别 一些行内名词简单解释&#xff1a; 3. 关于mysql 主要学什么 4. MySQL中重要的概念 4.1 概念 4…

RNN - 语言模型

语言模型 给定文本序列 x 1 , … , x T x_1, \ldots, x_T x1​,…,xT​&#xff0c;语言模型的目标是估计联合概率 p ( x 1 , … , x T ) p(x_1, \ldots, x_T) p(x1​,…,xT​)它的应用包括 做预训练模型&#xff08;eg BERT&#xff0c;GPT-3&#xff09;生成本文&#xff…

过拟合、归一化、正则化、鞍点

过拟合 过拟合的本质原因往往是因为模型具备方差很大的权重参数。 定义一个有4个特征的输入&#xff0c;特征向量为,定义一个模型&#xff0c;其只有4个参数&#xff0c;表示为。当模型过拟合时&#xff0c;这四个权重参数的方差会很大&#xff0c;可以假设为。当经过这个模型后…

【python画图】:从入门到精通绘制完美柱状图

目录 Python数据可视化&#xff1a;从入门到精通绘制完美柱状图一、基础篇&#xff1a;快速绘制柱状图1.1 使用Matplotlib基础绘制1.2 使用Pandas快速绘图 二、进阶篇&#xff1a;专业级柱状图定制2.1 多系列柱状图2.2 堆叠柱状图2.3 水平柱状图 三、专业参数速查表Matplotlib …

基础知识:离线安装docker、docker compose

(1)离线安装docker 确认版本:Ubuntu 18.04 LTS - bionic 确认架构:X86_64 lsb_release -a uname -a 官方指南:https://docs.docker.com/engine/install/ 选择Ubuntu,发现页面上最低是Ubuntu20.04, 不要紧

畅游Diffusion数字人(27):解读字节跳动提出主题定制视频生成技术Phantom

畅游Diffusion数字人(0):专栏文章导航 前言:主题定制视频生成,特别是zero-shot主题定制视频生成,一直是当前领域的一个难点,之前的方法效果很差。字节跳动提出了一个技术主题定制视频生成技术Phantom,效果相比于之前的技术进步非常显著。这篇博客详细解读一下这一工作。 …

《Adaptive Layer-skipping in Pre-trained LLMs》- 论文笔记

作者&#xff1a;Xuan Luo, Weizhi Wang, Xifeng Yan Department of Computer Science, UC Santa Barbara xuan_luoucsb.edu, weizhiwangucsb.edu, xyancs.ucsb.edu 1. 引言与动机 1.1 背景 LLM 的成功与挑战: 大型语言模型 (LLMs) 在翻译、代码生成、推理等任务上取得巨大成…

微信小程序实现table样式,自带合并行合并列

微信小程序在代码编写过程好像不支持原生table的使用&#xff0c;在开发过程中偶尔又得需要拿table来展示。 1.table效果展示 1.wxml <view class"table-container"><view class"table"><view class"table-row"><view cla…

电脑的品牌和配置

我的笔记本是2020年买的&#xff0c;之前的订单找不到了&#xff0c;就知道是联想&#xff0c;不清楚具体的配置。 本文来源&#xff1a;腾讯元宝 检查系统信息&#xff08;Windows&#xff09; 这通常是 ​​联想&#xff08;Lenovo&#xff09;​​ 的型号代码。 81XV 是联想…