NETool.Pack
2.5.3
See the version list below for details.
dotnet add package NETool.Pack --version 2.5.3
NuGet\Install-Package NETool.Pack -Version 2.5.3
<PackageReference Include="NETool.Pack" Version="2.5.3" />
<PackageVersion Include="NETool.Pack" Version="2.5.3" />
<PackageReference Include="NETool.Pack" />
paket add NETool.Pack --version 2.5.3
#r "nuget: NETool.Pack, 2.5.3"
#:package NETool.Pack@2.5.3
#addin nuget:?package=NETool.Pack&version=2.5.3
#tool nuget:?package=NETool.Pack&version=2.5.3
NETool.Pack
介绍
NETool.Pack 是 NETool 的适用于 C# 的零编码二进制序列化程序。
参考 MemoryPack,支持的类型不及其丰富,但足以满足大部分需求。
NETool.Pack 速度之所以如此之快,是由于其特定于 C# 优化的二进制格式,利用 .NET 8+ 和 C# 13 以及增量源生成器 IIncrementalGenerator(.NET Standard 2.0),另外包括 Span, ReadOnlySpan 以及内存池 ArrayPool 的使用。
除了二进制序列化,基于源生成还实现了与 Windows API 无关的 Ini 格式的配置文件读写, 方便用户可通过文本工具进行配置的修改。
软件架构
.Net8, .Net9, .Net10
安装教程
从 Nuget 安装最新版本。
Install-Package NETool.Pack
快速入门
定义要二进制序列化的类,并使用属性和关键字对其进行注释。[NEToolPackable] partial
定义要 Ini 格式序列化的类,并使用属性和关键字对其进行注释。[IniConfig(string fileName)] partial
using System.NETool;
[NEToolPackable]
[IniConfig("Person.ini")]
public partial class Person
{
public int Age { get; set; }
public string Name { get; set; }
[NEToolPackIgnore]
[IniConfigIgnore]
public string Address { get; set; }
}
注:NEToolPackable 与 IniConfig 特性可以单独按需要使用。
源生成的代码实现了 INEToolPackMembers 接口:
/// <summary>
/// NETool 序列化成员说明接口
/// </summary>
public interface INEToolPackMembers
{
/// <summary>
/// 排除数据字段
/// </summary>
string ExcludedMembers();
/// <summary>
/// 未知数据字段
/// </summary>
string UnknownMembers();
}
源生成的代码实现了 INEToolPackable 接口,用于二进制序列化:
/// <summary>
/// NETool 序列化接口
/// </summary>
public interface INEToolPackable
{
/// <summary>
/// NETool 序列化方法
/// </summary>
/// <param name="endian">字节序: Little 为小端字节(低字节序),Big 为大端字节序(高字节序)</param>
/// <param name="encoding">字符编码</param>
/// <param name="zipType">压缩及加密算法类型</param>
/// <param name="password">密码</param>
/// <returns>字节数组对象</returns>
ByteArray Serialize(Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null);
/// <summary>
/// NETool 反序列化方法
/// </summary>
/// <param name="span">数据</param>
/// <param name="endian">字节序: Little 为小端字节(低字节序),Big 为大端字节序(高字节序)</param>
/// <param name="encoding">字符编码</param>
/// <param name="zipType">压缩及加密算法类型</param>
/// <param name="password">密码</param>
void Deserialize(scoped ReadOnlySpan<byte> span, Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null);
}
另外还实现了两个深度拷贝函数:
/// <summary>
/// 获取已有 Sunny.Serialization.Demo.Person 对象的副本,需有默认的无参构造函数
/// </summary>
/// <returns>Sunny.Serialization.Demo.Person 副本</returns>
public Sunny.Serialization.Demo.Person DeepCopy()
/// <summary>
/// 将已有 Sunny.Serialization.Demo.Person 对象深度拷贝到另一个不为空的 Sunny.Serialization.Demo.Person 对象
/// </summary>
/// <param name="other">另一个 Sunny.Serialization.Demo.Person 对象</param>
public void DeepCopyTo(Sunny.Serialization.Demo.Person other)
源生成的代码实现了 IIniConfig 接口,用于 Ini 格式配置文件加载和保存:
/// <summary>
/// 定义一个接口,用于 Ini 格式配置文件加载和保存
/// </summary>
public interface IIniConfig
{
/// <summary>
/// 从文件加载配置
/// </summary>
void LoadIni();
/// <summary>
/// 保存配置到文件
/// </summary>
void SaveIni();
/// <summary>
/// 异步从文件加载配置
/// </summary>
Task LoadIniAsync();
/// <summary>
/// 异步保存配置到文件
/// </summary>
Task SaveIniAsync();
/// <summary>
/// 从文件加载配置
/// </summary>
/// <param name="fileName">文件名</param>
void LoadIni(string fileName);
/// <summary>
/// 保存配置到文件
/// </summary>
/// <param name="fileName">文件名</param>
void SaveIni(string fileName);
/// <summary>
/// 异步从文件加载配置
/// </summary>
/// <param name="fileName">文件名</param>
Task LoadIniAsync(string fileName);
/// <summary>
/// 异步保存配置到文件
/// </summary>
/// <param name="fileName">文件名</param>
Task SaveIniAsync(string fileName);
}
序列化代码由实现接口的 C# 源生成器功能生成。
- 在 Visual Studio 中,可以使用类名称上的快捷方式 F12 检查生成的代码,然后选择 *.Person.Pack.Properties.g.cs,此为二进制序列化生成代码:
// <auto-generated by NETool.Generator 2025-08-21 14:14:31/>
// ReSharper disable once InconsistentNaming
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.NETool;
using System.Runtime.CompilerServices;
using System.Text;
namespace Sunny.Serialization.Demo;
/// <summary>
/// Sunny.Serialization.Demo.Person 显示排除与未知的成员
/// </summary>
public partial class Person : INEToolPackMembers
{
/// <summary>
/// 排除的成员 1 个
/// </summary>
public string ExcludedMembers()
{
var sb = new ValueStringBuilder();
sb.AppendLine("忽略类型: string Address [标记 Ignore 特性;];");
return sb.ToString();
}
/// <summary>
/// 未知的成员 0 个
/// </summary>
public string UnknownMembers()
{
return string.Empty;
}
}
/// <summary>
/// Sunny.Serialization.Demo.Person 二进制序列化扩展
/// </summary>
public partial class Person : INEToolPackable
{
///<inheritdoc/>
public ByteArray Serialize(Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null)
{
var writer = new ByteArray(endian, encoding);
#region 序列化
// int Age
writer.WriteInt32(this.Age);
// string Name
writer.WriteString(this.Name);
#endregion 序列化
var result = zipType.Compress(writer.Span, password);
writer.Dispose();
return result;
}
///<inheritdoc/>
public void Deserialize(scoped ReadOnlySpan<byte> span, Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null)
{
var unZipped = zipType.Decompress(span, password);
var reader = new ByteArray(unZipped.Span, endian, encoding);
#region 反序列化
// int Age
this.Age = reader.ReadInt32();
// string Name
this.Name = reader.ReadString();
#endregion 反序列化
unZipped.Dispose();
}
/// <summary>
/// 获取已有 Sunny.Serialization.Demo.Person 对象的副本,需有默认的无参构造函数
/// </summary>
/// <returns>Sunny.Serialization.Demo.Person 副本</returns>
public Sunny.Serialization.Demo.Person DeepCopy()
{
using var writer = this.Serialize();
var copy = new Sunny.Serialization.Demo.Person();
copy.Deserialize(writer.Span);
return copy;
}
/// <summary>
/// 将已有 Sunny.Serialization.Demo.Person 对象深度拷贝到另一个不为空的 Sunny.Serialization.Demo.Person 对象
/// </summary>
/// <param name="other">另一个 Sunny.Serialization.Demo.Person 对象</param>
public void DeepCopyTo(Sunny.Serialization.Demo.Person other)
{
if (other is null) return;
using var writer = this.Serialize();
other.Deserialize(writer.Span);
}
}
调用序列化/反序列化对象实例:
var person = new Person
{
Age = 30,
Name = "Sunny"
};
// 序列化
var byteArray = person.Serialize();
Console.WriteLine($"Serialized Person: {byteArray.Span.ToHexString()}");
// 反序列化
person.Deserialize(byteArray.Span);
Console.WriteLine($"Deserialized Person: Age={person.Age}, Name={person.Name}");
byteArray.Dispose();
// 深拷贝
Person other = person.DeepCopy();
Console.WriteLine($"Deep Copied Person: Age={other.Age}, Name={other.Name}");
输出结果:
Serialized Person: 1E0000000553756E6E79
Deserialized Person: Age=30, Name=Sunny
Deep Copied Person: Age=30, Name=Sunny
- 在 Visual Studio 中,可以使用类名称上的快捷方式 F12 检查生成的代码,然后选择 *.Person.Ini.Properties.g.cs,此为 Ini 格式配置文件生成代码:
// <auto-generated by NETool.Generator 2025-08-21 14:48:50/>
// ReSharper disable once InconsistentNaming
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.NETool;
using System.Runtime.CompilerServices;
using System.Text;
namespace Sunny.Serialization.Demo;
/// <summary>
/// Sunny.Serialization.Demo.Person Ini 配置文件序列化扩展
/// </summary>
public partial class Person : IIniConfig
{
///<inheritdoc/>
public void SaveIni(string fileName)
{
var writer = __CreateIniWriter(fileName);
writer.SaveAs(fileName);
}
///<inheritdoc/>
public Task SaveIniAsync(string fileName)
{
var writer = __CreateIniWriter(fileName);
return writer.SaveAsAsync(fileName);
}
///<inheritdoc/>
public void SaveIni()
{
SaveIni(FileEx.VerifyFileName("Person.ini"));
}
///<inheritdoc/>
public Task SaveIniAsync()
{
return SaveIniAsync(FileEx.VerifyFileName("Person.ini"));
}
///<inheritdoc/>
public void LoadIni(string fileName)
{
var reader = new IniFile(fileName, Encoding.UTF8, false);
reader.Load();
__LoadFromIniReader(reader);
}
///<inheritdoc/>
public async Task LoadIniAsync(string fileName)
{
var reader = new IniFile(fileName, Encoding.UTF8, false);
await reader.LoadAsync().ConfigureAwait(false);
__LoadFromIniReader(reader);
}
///<inheritdoc/>
public void LoadIni()
{
LoadIni(FileEx.VerifyFileName("Person.ini"));
}
///<inheritdoc/>
public Task LoadIniAsync()
{
return LoadIniAsync(FileEx.VerifyFileName("Person.ini"));
}
/// <summary>
/// 创建一个 IniFile 写入器
/// </summary>
/// <param name="fileName">配置文件名</param>
/// <returns>IniFile 写入器</returns>
private IniFile __CreateIniWriter(string fileName)
{
var writer = new IniFile(fileName, Encoding.UTF8, false);
#region 序列化
var session = "Sunny.Serialization.Demo.Person";
// int Age
writer.WriteInt32(session, "Age", this.Age);
// string Name
writer.WriteString(session, "Name", this.Name);
#endregion 序列化
return writer;
}
/// <summary>
/// 从 IniFile 读取器加载
/// </summary>
/// <param name="reader">IniFile 读取器</param>
private void __LoadFromIniReader(IniFile reader)
{
#region 反序列化
var session = "Sunny.Serialization.Demo.Person";
// int Age
this.Age = reader.ReadInt32(session, "Age", this.Age);
// string Name
this.Name = reader.ReadString(session, "Name", this.Name);
#endregion 反序列化
}
}
调用 Ini 读写序列化/反序列化对象实例:
var person = new Person
{
Age = 30,
Name = "Sunny"
};
await person.SaveIniAsync();
var other2 = new Person();
await other2.LoadIniAsync().ConfigureAwait(false);
Console.WriteLine($"Ini load Person: Age={other2.Age}, Name={other2.Name}");
输出结果:
Ini load Person: Age=30, Name=Sunny
保存的配置文件 Person.ini 在运行程序的根目录:
;<?Ini Version="NETool IniFile V1.0.1" Encoding="utf-8" Updated="2025-08-21 10:50:07"?>
[Sunny.Serialization.Demo.Person]
Age=30
Name=Sunny
内置支持的类型
1 基础类型: bool, byte, sbyte, short, ushort, int, uint, long, ulong, System.Half, float, double, decimal, char;
2 扩展类型: 原生的 string, DateTime, DateTimeOffset, Point, PointF, Size, SizeF, Color, Rectangle, RectangleF, TimeSpan, Guid, Version, Uri, TimeZoneInfo, CultureInfo 类型,System.NETool 扩展的 IpV4, IpV4Point, GuidV7, LngLat, SystemTime, MiniSystemTime 类型;
3 枚举类型: enum;
4 结构类型: struct, 标记为 [InlineArray(n)] 特性的结构体;
5 结构类型: struct, 标记为 [StructLayout(LayoutKind.Explicit)] 特性的结构体;
6 可序列化类: class, 标记为 [NEToolPackable] 特性的类,类必须增加 partial 关键字,并有无参数的构造函数;
7 一维数组:
T[]
, 其中 T 是上述 1、2、3、4、5 、6类型之一;8 列表:
List<T>
,ConcurrentList<T>
, 其中 T 是上述 1、2、3、4、5 、6类型之一;9 字典:
Dictionary<TKey, TValue>
,ConcurrentDictionary<TKey, TValue>
, 其中 TKey 和 TValue 是上述 1、2、3、4、5、6 类型之一;
类只有1 基础类型时,序列化与原生的 System.IO.BinaryWriter 完全一致
定义 [NEToolPackable] [IniConfig] class
[NEToolPackable] 和 [IniConfig] 特性注释 class 类,定义为 public 或者 internal,类必须增加 partial 关键字,并有无参数的构造函数。类不能为继承的子类。
类序列化的字段包含:
- 字段 (filed) ,必须标记为 public,
- 属性 (Property),必须标记为 public,并且有公开的 get;set;
标记为 [NEToolPackIgnore] 或者 [IniConfigIgnore] 或者 [IgnoreDataMember] 或者带有其他 Ignore 特性的,序列化时将会忽略。
枚举生成 Description 扩展方法
NETool.Pack 会通过源生成枚举类的 Description 扩展方法,例如:
public enum TestEnum : byte
{
[Description("Excellent")]
A = 0,
[Description("Perfect")]
B = 1,
[Description("Good")]
C = 2,
[Description("Average")]
D = 3,
[Description("Failure")]
E = 4,
F = 5,
}
源生成的代码在 *.TestEnum.Desc.g.cs
/// <summary>
/// Sunny.Serialization.Demo.TestEnum 枚举的描述扩展方法
/// </summary>
public static class Sunny_Serialization_Demo_TestEnum_Description_Extensions
{
/// <summary>
/// 获取 Sunny.Serialization.Demo.TestEnum 枚举值的描述
/// </summary>
/// <param name="value">枚举值</param>
/// <returns>枚举值的描述</returns>
public static string Description(this Sunny.Serialization.Demo.TestEnum value)
{
return value switch
{
Sunny.Serialization.Demo.TestEnum.A => "Excellent",
Sunny.Serialization.Demo.TestEnum.B => "Perfect",
Sunny.Serialization.Demo.TestEnum.C => "Good",
Sunny.Serialization.Demo.TestEnum.D => "Average",
Sunny.Serialization.Demo.TestEnum.E => "Failure",
Sunny.Serialization.Demo.TestEnum.F => "F",
_ => string.Empty
};
}
}
枚举条目有 [Description] 特性的,输出特性描述文本。没有此特性的,输出枚举名称。
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- NETool (>= 2.5.3)
- NETool.Generator (>= 2.5.3)
-
net8.0
- NETool (>= 2.5.3)
- NETool.Generator (>= 2.5.3)
-
net9.0
- NETool (>= 2.5.3)
- NETool.Generator (>= 2.5.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
2.5.5 | 0 | 8/22/2025 |
2.5.3 | 9 | 8/21/2025 |
1.0.2 | 6 | 8/21/2025 |
1.0.1 | 9 | 8/21/2025 |
1.0.0 | 10 | 8/21/2025 |
0.8.0 | 11 | 8/20/2025 |
0.7.2 | 10 | 8/20/2025 |
0.7.1 | 15 | 8/19/2025 |
0.7.0 | 90 | 8/14/2025 |
0.6.3 | 91 | 8/14/2025 |
0.6.2 | 91 | 8/12/2025 |
0.6.1 | 96 | 8/12/2025 |
0.6.0 | 96 | 8/12/2025 |
0.5.5 | 86 | 8/11/2025 |
0.5.3 | 86 | 8/11/2025 |
0.5.2 | 67 | 8/9/2025 |
0.5.1 | 185 | 8/7/2025 |
0.5.0 | 183 | 8/7/2025 |
0.4.0 | 194 | 8/6/2025 |
0.3.0 | 192 | 8/5/2025 |
0.2.0 | 177 | 8/5/2025 |