C# 序列化技术全面解析:原理、实现与应用场景

news2025/6/6 19:11:21

在软件开发中,数据持久化和网络通信是两个至关重要的环节。想象一下,当我们需要将一个复杂的对象保存到文件中,或者通过网络发送到另一台计算机时,如何有效地表示这个对象?这就是序列化技术要解决的问题。序列化(Serialization)是将对象转换为可存储或传输的格式的过程,而反序列化(Deserialization)则是将这些数据重新转换为对象的过程。

C# 作为一门成熟的面向对象编程语言,提供了丰富多样的序列化解决方案。本文将全面探讨 C# 中的各种序列化技术,包括二进制序列化、XML 序列化、JSON 序列化以及数据契约序列化,分析它们的原理、实现方式、优缺点以及适用场景,并通过实际代码示例展示如何在项目中应用这些技术。

一、序列化基础概念

1.1 什么是序列化

序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。在序列化过程中,对象将其当前状态(通常是其成员变量的值)写入到临时或持久性存储区。之后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

1.2 为什么需要序列化

序列化技术主要解决以下几个问题:

  1. 数据持久化:将对象状态保存到文件或数据库中,以便后续重新加载

  2. 远程通信:在不同应用程序域或网络中的计算机之间传输对象

  3. 进程间通信:在不同进程之间传递复杂数据结构

  4. 缓存机制:将对象缓存到内存或分布式缓存中

1.3 C# 中的序列化分类

C# 提供了多种序列化方式,主要可以分为以下几类:

  1. 二进制序列化

  2. XML 序列化

  3. JSON 序列化

  4. 数据契约序列化

  5. 自定义序列化

每种方式都有其特点和适用场景,开发者需要根据具体需求选择合适的序列化方式。

二、二进制序列化

2.1 二进制序列化概述

二进制序列化是将对象转换为二进制格式的过程,这种格式通常非常紧凑且处理速度快。在 .NET Framework 中,可以使用 BinaryFormatter 类来实现二进制序列化。

2.2 实现二进制序列化

下面是一个完整的二进制序列化示例:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    [NonSerialized]
    public string TemporaryData; // 这个字段不会被序列化
}

public class BinarySerializationDemo
{
    public static void Demo()
    {
        Person person = new Person { Name = "张三", Age = 30, TemporaryData = "临时数据" };
        
        // 序列化
        byte[] serializedData;
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, person);
            serializedData = stream.ToArray();
        }
        
        Console.WriteLine($"序列化后的字节数: {serializedData.Length}");
        
        // 反序列化
        using (MemoryStream stream = new MemoryStream(serializedData))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            Person deserializedPerson = (Person)formatter.Deserialize(stream);
            
            Console.WriteLine($"姓名: {deserializedPerson.Name}");
            Console.WriteLine($"年龄: {deserializedPerson.Age}");
            Console.WriteLine($"临时数据: {deserializedPerson.TemporaryData ?? "null"}");
        }
    }
}

2.3 二进制序列化的特点

优点:

  1. 序列化后的数据非常紧凑,占用空间小

  2. 序列化和反序列化速度快

  3. 可以完整保留对象图和类型信息

缺点:

  1. 数据不可读,难以调试

  2. 平台依赖性较强

  3. 在 .NET Core/.NET 5+ 中被认为不安全,已不建议使用

2.4 安全注意事项

由于 BinaryFormatter 存在严重的安全风险,微软已从 .NET Core 开始不推荐使用它。攻击者可能利用它执行任意代码。如果确实需要使用二进制序列化,可以考虑以下替代方案:

  1. 使用 System.Text.Json 或 Newtonsoft.Json 进行 JSON 序列化

  2. 使用 XmlSerializer 进行 XML 序列化

  3. 实现自定义的二进制序列化

三、XML 序列化

3.1 XML 序列化概述

XML 序列化将对象的公共属性和字段转换为 XML 格式。与二进制序列化不同,XML 序列化不包含类型信息,只序列化公共属性和字段。

3.2 实现 XML 序列化

using System;
using System.IO;
using System.Xml.Serialization;

[Serializable]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    [XmlIgnore]
    public DateTime CreatedAt { get; set; } // 这个属性不会被序列化
}

public class XmlSerializationDemo
{
    public static void Demo()
    {
        Product product = new Product 
        { 
            Id = 1001, 
            Name = "笔记本电脑", 
            Price = 5999.99m,
            CreatedAt = DateTime.Now
        };
        
        // 序列化
        XmlSerializer serializer = new XmlSerializer(typeof(Product));
        string xmlString;
        using (StringWriter writer = new StringWriter())
        {
            serializer.Serialize(writer, product);
            xmlString = writer.ToString();
        }
        
        Console.WriteLine("序列化的XML:");
        Console.WriteLine(xmlString);
        
        // 反序列化
        using (StringReader reader = new StringReader(xmlString))
        {
            Product deserializedProduct = (Product)serializer.Deserialize(reader);
            
            Console.WriteLine($"\n反序列化结果:");
            Console.WriteLine($"ID: {deserializedProduct.Id}");
            Console.WriteLine($"名称: {deserializedProduct.Name}");
            Console.WriteLine($"价格: {deserializedProduct.Price}");
            Console.WriteLine($"创建时间: {deserializedProduct.CreatedAt}");
        }
    }
}

3.3 XML 序列化的特点

优点:

  1. 生成的 XML 可读性强

  2. 跨平台兼容性好

  3. 可以通过 XSD 验证数据格式

  4. 支持通过属性精细控制序列化过程

缺点:

  1. 数据冗余多,文件体积较大

  2. 序列化和反序列化性能较低

  3. 只能序列化公共成员

3.4 XML 序列化高级控制

通过使用各种 XML 特性,可以精细控制序列化过程:

[XmlRoot("ProductItem")]
public class AdvancedProduct
{
    [XmlAttribute("productId")]
    public int Id { get; set; }
    
    [XmlElement("productName")]
    public string Name { get; set; }
    
    [XmlElement("productPrice")]
    public decimal Price { get; set; }
    
    [XmlElement("isAvailable")]
    public bool IsAvailable { get; set; }
    
    [XmlArray("Categories")]
    [XmlArrayItem("Category")]
    public List<string> Categories { get; set; }
}

四、JSON 序列化

4.1 JSON 序列化概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。在 Web 开发和 API 设计中,JSON 已成为事实上的标准。

C# 中有两种主要的 JSON 序列化实现:

  1. System.Text.Json (.NET Core 3.0 及以后版本内置)

  2. Newtonsoft.Json (流行的第三方库)

4.2 使用 System.Text.Json 实现 JSON 序列化

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public class Order
{
    public int OrderId { get; set; }
    public string CustomerName { get; set; }
    
    [JsonPropertyName("items")]
    public List<OrderItem> OrderItems { get; set; }
    
    [JsonIgnore]
    public string InternalNote { get; set; }
}

public class OrderItem
{
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
}

public class SystemTextJsonDemo
{
    public static void Demo()
    {
        Order order = new Order
        {
            OrderId = 1001,
            CustomerName = "李四",
            InternalNote = "重要客户",
            OrderItems = new List<OrderItem>
            {
                new OrderItem { ProductName = "鼠标", Quantity = 2, UnitPrice = 89.50m },
                new OrderItem { ProductName = "键盘", Quantity = 1, UnitPrice = 199.00m }
            }
        };
        
        // 序列化选项
        var options = new JsonSerializerOptions
        {
            WriteIndented = true, // 美化输出
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase // 驼峰命名
        };
        
        // 序列化
        string jsonString = JsonSerializer.Serialize(order, options);
        Console.WriteLine("序列化的JSON:");
        Console.WriteLine(jsonString);
        
        // 反序列化
        Order deserializedOrder = JsonSerializer.Deserialize<Order>(jsonString, options);
        Console.WriteLine($"\n反序列化结果 - 订单ID: {deserializedOrder.OrderId}");
        Console.WriteLine($"客户名称: {deserializedOrder.CustomerName}");
        Console.WriteLine($"订单项数: {deserializedOrder.OrderItems?.Count ?? 0}");
    }
}

4.3 使用 Newtonsoft.Json 实现 JSON 序列化

using System;
using Newtonsoft.Json;

public class NewtonsoftJsonDemo
{
    public static void Demo()
    {
        var data = new
        {
            Name = "王五",
            Age = 35,
            IsActive = true,
            LastLogin = DateTime.Now,
            Scores = new[] { 90, 85, 95 }
        };
        
        // 序列化设置
        var settings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            NullValueHandling = NullValueHandling.Ignore,
            DateFormatString = "yyyy-MM-dd HH:mm:ss"
        };
        
        // 序列化
        string json = JsonConvert.SerializeObject(data, settings);
        Console.WriteLine("使用Newtonsoft.Json序列化的JSON:");
        Console.WriteLine(json);
        
        // 反序列化
        var deserializedData = JsonConvert.DeserializeAnonymousType(json, data, settings);
        Console.WriteLine($"\n反序列化结果 - 姓名: {deserializedData.Name}");
        Console.WriteLine($"年龄: {deserializedData.Age}");
    }
}

4.4 JSON 序列化的特点

优点:

  1. 数据格式轻量,文件体积小

  2. 可读性较好

  3. 广泛支持于各种编程语言和平台

  4. 在 Web 开发中已成为标准

缺点:

  1. 相比二进制格式,仍然有一定冗余

  2. 处理某些复杂类型(如循环引用)需要额外配置

4.5 System.Text.Json vs Newtonsoft.Json

特性System.Text.JsonNewtonsoft.Json
性能更高较低
内存分配更少较多
功能丰富度基本功能非常丰富
内置支持.NET Core 3.0+需要安装NuGet包
异步序列化支持不支持
处理循环引用有限支持完善支持

对于新项目,建议优先使用 System.Text.Json,除非需要 Newtonsoft.Json 的某些特有功能。

五、数据契约序列化

5.1 数据契约序列化概述

数据契约序列化是 WCF (Windows Communication Foundation) 中使用的一种序列化机制,通过 DataContractSerializer 类实现。它比 XML 序列化更灵活,但需要显式标记要序列化的成员。

5.2 实现数据契约序列化

using System;
using System.IO;
using System.Runtime.Serialization;

[DataContract]
public class Employee
{
    [DataMember(Name = "id")]
    public int EmployeeId { get; set; }
    
    [DataMember]
    public string Name { get; set; }
    
    [DataMember(Order = 3)]
    public string Department { get; set; }
    
    public string SecretCode { get; set; } // 不会被序列化
}

public class DataContractSerializationDemo
{
    public static void Demo()
    {
        Employee emp = new Employee
        {
            EmployeeId = 1001,
            Name = "赵六",
            Department = "研发部",
            SecretCode = "ABC123"
        };
        
        // 序列化
        DataContractSerializer serializer = new DataContractSerializer(typeof(Employee));
        string xmlString;
        using (var stream = new MemoryStream())
        {
            serializer.WriteObject(stream, emp);
            stream.Position = 0;
            using (var reader = new StreamReader(stream))
            {
                xmlString = reader.ReadToEnd();
            }
        }
        
        Console.WriteLine("数据契约序列化的XML:");
        Console.WriteLine(xmlString);
        
        // 反序列化
        using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xmlString)))
        {
            Employee deserializedEmp = (Employee)serializer.ReadObject(stream);
            Console.WriteLine($"\n反序列化结果 - ID: {deserializedEmp.EmployeeId}");
            Console.WriteLine($"姓名: {deserializedEmp.Name}");
            Console.WriteLine($"部门: {deserializedEmp.Department}");
            Console.WriteLine($"密码: {deserializedEmp.SecretCode ?? "null"}");
        }
    }
}

5.3 数据契约序列化的特点

优点:

  1. 对序列化过程有更精细的控制

  2. 支持版本控制,对数据变更更友好

  3. 可以处理复杂对象图和继承层次结构

  4. 性能优于 XML 序列化

缺点:

  1. 需要显式标记要序列化的成员

  2. 生成的 XML 不如 XmlSerializer 生成的那么简洁

  3. 主要用于 WCF 服务

六、序列化技术选型指南

在选择序列化技术时,应考虑以下因素:

  1. 性能需求:二进制 > JSON ≈ 数据契约 > XML

  2. 数据大小:二进制 < JSON < 数据契约 < XML

  3. 可读性:XML ≈ JSON > 数据契约 > 二进制

  4. 跨平台支持:JSON > XML > 数据契约 > 二进制

  5. 类型安全:二进制 > 数据契约 > XML ≈ JSON

  6. 安全考虑:JSON ≈ XML > 数据契约 > 二进制

推荐场景:

  • Web API/前后端通信:JSON (System.Text.Json 或 Newtonsoft.Json)

  • 配置文件:JSON 或 XML

  • 高性能本地存储:考虑自定义二进制格式或 Protocol Buffers

  • WCF 服务:数据契约序列化

  • 临时对象存储:二进制序列化(仅限可信环境)

七、高级主题与最佳实践

7.1 处理循环引用

循环引用是指对象之间相互引用形成的环。默认情况下,许多序列化器无法处理这种情况。

在 Newtonsoft.Json 中处理循环引用:

var settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    ReferenceLoopHandling = ReferenceLoopHandling.Serialize
};
string json = JsonConvert.SerializeObject(obj, settings);

在 System.Text.Json 中处理循环引用:

var options = new JsonSerializerOptions
{
    ReferenceHandler = ReferenceHandler.Preserve
};
string json = JsonSerializer.Serialize(obj, options);

 

7.2 自定义序列化

对于需要特殊处理的类型,可以实现自定义序列化逻辑:

public class CustomObject : IJsonOnSerializing, IJsonOnSerialized, 
                          IJsonOnDeserializing, IJsonOnDeserialized
{
    public string Data { get; set; }
    
    void IJsonOnSerializing.OnSerializing()
    {
        Console.WriteLine("序列化前调用");
    }
    
    void IJsonOnSerialized.OnSerialized()
    {
        Console.WriteLine("序列化后调用");
    }
    
    void IJsonOnDeserializing.OnDeserializing()
    {
        Console.WriteLine("反序列化前调用");
    }
    
    void IJsonOnDeserialized.OnDeserialized()
    {
        Console.WriteLine("反序列化后调用");
    }
}

7.3 版本兼容性考虑

在设计可序列化类型时,应考虑未来可能的变更:

  1. 避免删除已序列化的字段,可以标记为废弃

  2. 新添加的字段应提供合理的默认值

  3. 考虑使用 [OptionalField] 特性标记可能不存在的字段

  4. 实现 ISerializable 接口进行自定义版本控制

7.4 性能优化建议

  1. 对于频繁序列化的类型,缓存序列化器实例

  2. 对于大型对象,考虑流式序列化

  3. 使用 ArrayPool<byte> 减少内存分配

  4. 在 ASP.NET Core 中,使用 System.Text.Json 源生成器

八、结论

C# 提供了丰富多样的序列化技术,每种技术都有其适用场景。在现代应用开发中,JSON 序列化已成为最常用的方式,特别是对于 Web API 和前后端通信。System.Text.Json 作为 .NET 平台的新标准,提供了高性能和低内存占用的优势,而 Newtonsoft.Json 则因其丰富的功能仍然在许多项目中使用。

对于需要更高性能的场景,可以考虑二进制序列化,但应注意其安全风险。XML 序列化在需要严格模式验证或与旧系统集成的场景中仍然有价值。数据契约序列化则是 WCF 服务开发的首选。

选择序列化技术时,开发者应综合考虑性能需求、数据大小、可读性要求、跨平台需求和安全性等因素。理解各种序列化技术的原理和特点,能够帮助我们在实际项目中做出更合理的技术选型,构建更健壮、高效的应用程序。

 

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

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

相关文章

electron定时任务,打印内存占用情况

// 监听更新 function winUpdate(){// 每次执行完后重新设置定时器try {// 获取当前时间并格式化为易读的字符串const now new Date();const timeString now.toLocaleString();console.log(当前时间: ${timeString});// 记录内存使用情况&#xff08;可选&#xff09;const m…

Gitee Wiki:以知识管理赋能 DevSecOps,推动关键领域软件自主演进

关键领域软件研发中的知识管理困境 传统文档管理模式问题显著 关键领域软件研发领域&#xff0c;传统文档管理模式问题显著&#xff1a;文档存储无系统&#xff0c;查找困难&#xff0c;降低效率&#xff1b;更新不及时&#xff0c;与实际脱节&#xff0c;误导开发&#xff1…

学习STC51单片机24(芯片为STC89C52RCRC)

每日一言 把 “我不行” 换成 “我试试”&#xff0c;你会发现一片新的天地。 那关于优化 白盒测试 我们之前不是通过这个接线方式可以看到返回到信息嘛因为安信可的特性就是返回Esp8266的反馈&#xff0c;可以看到代码死在哪里了&#xff0c;导致连接不上&#xff0c;因为我们…

LabVIEW基于 DataSocket从 OPC 服务器读取数据

LabVIEW 中基于 DataSocket 函数从 OPC 服务器读取数据的功能&#xff0c;为工业自动化等场景下的数据交互提供了解决方案。通过特定函数实现 URL 指定、连接建立与管理、数据读取&#xff0c;相比传统 Socket 通信和 RESTful API &#xff0c;在 OPC 服务器数据交互场景有适配…

阿里云无影云桌面深度测评

阿里云无影桌面深度测评&#xff1a;解锁云端工作“新范式”的“未来之钥”&#xff01; 在数字化浪潮席卷全球的2025年&#xff0c;远程办公与混合办公已不再是权宜之计&#xff0c;而是职场不可逆转的新常态。然而&#xff0c;如何确保员工无论身在何处&#xff0c;都能拥有…

深入浅出:Oracle 数据库 SQL 执行计划查看详解(1)——基础概念与查看方式

背景 在当今的软件开发领域&#xff0c;尽管主流开发模式往往倾向于采用单表模式&#xff0c;力图尽可能地减少表之间的连接操作&#xff0c;以期达到提高数据处理效率、简化应用逻辑等目的。然而&#xff0c;对于那些已经上线运行多年的运维老系统而言&#xff0c;它们内部往…

前端​​HTML contenteditable 属性使用指南

​​什么是 contenteditable&#xff1f; HTML5 提供的全局属性&#xff0c;使元素内容可编辑类似于简易富文本编辑器兼容性​​ 支持所有现代浏览器&#xff08;Chrome、Firefox、Safari、Edge&#xff09; 移动端&#xff08;iOS/Android&#xff09;部分键盘行为需测试 &l…

自动化采集脚本与隧道IP防封设计

最近群里讨论问如何编写一个自动化采集脚本&#xff0c;要求使用隧道IP&#xff08;代理IP池&#xff09;来防止IP被封。这样的脚本通常用于爬虫或数据采集任务&#xff0c;其中目标网站可能会因为频繁的请求而封禁IP。对于这些我还是有些经验的。 核心思路&#xff1a; 1、使…

【设计模式-4.7】行为型——备忘录模式

说明&#xff1a;本文介绍行为型设计模式之一的备忘录模式 定义 备忘录模式&#xff08;Memento Pattern&#xff09;又叫作快照模式&#xff08;Snapshot Pattern&#xff09;或令牌模式&#xff08;Token Pattern&#xff09;指在不破坏封装的前提下&#xff0c;捕获一个对…

docker离线镜像下载

背景介绍 在某些网络受限的环境中&#xff0c;直接从Docker Hub或其他在线仓库拉取镜像可能会遇到困难。为了在这种情况下也能顺利使用Docker镜像&#xff0c;我们可以提前下载好所需的镜像&#xff0c;并通过离线方式分发和使用。 当前镜像有&#xff1a;python-3.8-slim.ta…

Vert.x学习笔记-Verticle原理解析

Vert.x学习笔记 一、设计理念&#xff1a;事件驱动的组件化模型二、生命周期管理三、部署方式与策略四、通信机制&#xff1a;事件总线&#xff08;Event Bus&#xff09;五、底层实现原理六、典型应用场景七、Verticle与EventLoop的关系1、核心关系&#xff1a;一对一绑定与线…

jQuery和CSS3卡片列表布局特效

这是一款jQuery和CSS3卡片列表布局特效。该卡片布局使用owl.carousel.js来制作轮播效果&#xff0c;使用简单的css代码来制作卡片布局&#xff0c;整体效果时尚大方。 预览 下载 使用方法 在页面最后引入jquery和owl.carousel.js相关文件。 <link rel"stylesheet&qu…

不连网也能跑大模型?

一、这是个什么 App&#xff1f; 你有没有想过&#xff0c;不用连网&#xff0c;你的手机也能像 ChatGPT 那样生成文字、识别图片、甚至回答复杂问题&#xff1f;Google 最近悄悄发布了一个实验性 Android 应用——AI Edge Gallery&#xff0c;就是为此而生的。 这个应用不在…

强化学习鱼书(10)——更多深度强化学习的算法

&#xff1a;是否使用环境模型&#xff08;状态迁移函数P(s’|s,a)和奖 励函数r(s&#xff0c;a&#xff0c;V)&#xff09;。不使用环境模型的方法叫作无模型&#xff08;model-free&#xff09;的方法&#xff0c;使用环境模型的方法叫作有模型&#xff08;model-based&#…

K8S上使用helm部署 Prometheus + Grafana

一、使用 Helm 安装 Prometheus 1. 配置源 地址&#xff1a;prometheus 27.19.0 prometheus/prometheus-community # 添加repo $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts "prometheus-community" has been added…

Java面试八股--07-项目篇

致谢:2025年 Java 面试八股文(20w字)_java面试八股文-CSDN博客 目录 1、介绍一下最近做的项目 1.1 项目背景: 1.2 项目功能 1.3 技术栈 1.4自己负责的功能模块 1.5项目介绍参考: 1.6整体业务介绍: 1.8后台管理系统功能: 1.8.1后台主页: 1.8.2 商品模块: 1.8…

MCP架构全解析:从核心原理到企业级实践

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

从0到1认识EFK

一、ES集群部署 操作系统Ubuntu22.04LTS/主机名IP地址主机配置elk9110.0.0.91/244Core8GB100GB磁盘elk9210.0.0.92/244Core8GB100GB磁盘elk9310.0.0.93/244Core8GB100GB磁盘 1. 什么是ElasticStack? # 官网 https://www.elastic.co/ ElasticStack早期名称为elk。 elk分别…

定制开发开源AI智能名片驱动下的海报工厂S2B2C商城小程序运营策略——基于社群口碑传播与子市场细分的实证研究

摘要 本文聚焦“定制开发开源AI智能名片S2B2C商城小程序”技术与海报工厂业务的融合实践&#xff0c;探讨其如何通过风格化海报矩阵的精细化开发、AI技术驱动的用户体验升级&#xff0c;以及S2B2C模式下的社群裂变机制&#xff0c;实现“工具功能-社交传播-商业变现”的生态…

【Unity开发】控制手机移动端的震动

&#x1f43e; 个人主页 &#x1f43e; 阿松爱睡觉&#xff0c;横竖醒不来 &#x1f3c5;你可以不屠龙&#xff0c;但不能不磨剑&#x1f5e1; 目录 一、前言二、Unity的Handheld.Vibrate()三、调用Android原生代码四、NiceVibrations插件五、DeviceVibration插件六、控制游戏手…