NETool.Pack 2.5.3

There is a newer version of this package available.
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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NETool.Pack" Version="2.5.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NETool.Pack" Version="2.5.3" />
                    
Directory.Packages.props
<PackageReference Include="NETool.Pack" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NETool.Pack --version 2.5.3
                    
#r "nuget: NETool.Pack, 2.5.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NETool.Pack@2.5.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NETool.Pack&version=2.5.3
                    
Install as a Cake Addin
#tool nuget:?package=NETool.Pack&version=2.5.3
                    
Install as a Cake Tool

SunnyUI.Net

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] 特性的,输出特性描述文本。没有此特性的,输出枚举名称。

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

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