Soul.SqlSharp 1.0.0-beta.5

This is a prerelease version of Soul.SqlSharp.
dotnet add package Soul.SqlSharp --version 1.0.0-beta.5
                    
NuGet\Install-Package Soul.SqlSharp -Version 1.0.0-beta.5
                    
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="Soul.SqlSharp" Version="1.0.0-beta.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Soul.SqlSharp" Version="1.0.0-beta.5" />
                    
Directory.Packages.props
<PackageReference Include="Soul.SqlSharp" />
                    
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 Soul.SqlSharp --version 1.0.0-beta.5
                    
#r "nuget: Soul.SqlSharp, 1.0.0-beta.5"
                    
#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 Soul.SqlSharp@1.0.0-beta.5
                    
#: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=Soul.SqlSharp&version=1.0.0-beta.5&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Soul.SqlSharp&version=1.0.0-beta.5&prerelease
                    
Install as a Cake Tool

Soul.SqlSharp

Soul.SqlSharp 是 C# 版本的轻量级 SQL ORM,核心行为对齐仓颉 sqlsharp,面向直接 SQL、简单实体映射、变更跟踪和高性能物化场景。

当前版本仍是 beta。公开 API 会继续按仓颉版本和性能目标收敛;预览期不承诺长期二进制兼容。

方向 能力 价值
高性能查询 实体和 POCO 物化使用 Reflection.Emit / DynamicMethod 生成专用委托 查询结果按列 ordinal 直接读取并写入属性,减少反射调用、重复列名匹配、中间对象和多阶段转换成本
命名参数 SQL 使用 @name 参数,支持匿名对象、普通对象、DictionaryDbParameters 和集合参数 调用侧不用维护位置参数顺序;IN @ids 这类集合条件可自动展开,同时最终只绑定 SQL 中真实出现的参数
链式查询 DbSet<T> 支持字符串 SQL 片段,也支持 Where(x => ...)Select(x => ...) 等表达式重载 简单查询可以类型安全地写条件和投影;复杂 SQL 仍可直接落到字符串片段,保留对最终 SQL 的控制
变更跟踪 自动记录实体状态和原始值,SaveChanges() 统一提交 插入、更新、删除走同一工作单元;更新只提交变化列,支持显式 UpdateDetach、只读查询和并发检查
类型转换 ValueConverter 统一处理实体属性的数据库值、参数值和存储值比较 强类型 ID、金额对象、JSON 字段等业务类型可以保留领域建模,不把运行时类型映射接口暴露成公开扩展点
模型配置 DataAnnotations 与 Fluent API 均可使用,Fluent API 优先级更高 简单模型靠约定和注解,复杂模型用集中式配置覆盖,行为和仓颉版本保持同类口径

核心功能包括原生 SQL、链式 DbSet<T> 查询、表达式查询、分页、聚合、投影、变更跟踪、自增主键、字符串主键、复合主键、并发检查、JSON 转换、自定义 ValueConverter 和高性能物化。

安装

dotnet add package Soul.SqlSharp --prerelease

数据库驱动由业务项目自行选择和引用,例如:

dotnet add package MySqlConnector
dotnet add package Npgsql

当前包目标框架:

Target Framework 说明
net6.0 LTS 项目可用
net8.0 LTS 项目可用
net10.0 面向新版本运行时

快速开始

using MySqlConnector;
using Soul.SqlSharp;
using Soul.SqlSharp.Metadata;

var options = new DbContextOptionsBuilder()
    .UseConnectionFactory(() => new MySqlConnection(connectionString))
    .UseIdentitySql("SELECT LAST_INSERT_ID()")
    .Build();

using var db = new AppDbContext(options);

var user = db.Users
    .Params(new { account = "admin" })
    .Where("account = @account")
    .FirstOrDefault();

public sealed class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions options)
        : base(options)
    {
    }

    public DbSet<User> Users => Set<User>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .ToTable("sys_user")
            .HasKey(x => x.Id)
            .Property(x => x.Id, p => p.ValueGeneratedOnAdd())
            .Property(x => x.Account, p => p.HasColumnName("account"));
    }
}

public sealed class User
{
    public long Id { get; set; }

    public string Account { get; set; } = string.Empty;

    public string Name { get; set; } = string.Empty;

    public int Age { get; set; }

    public DateTime? DeletedAt { get; set; }
}

实体定义

Soul.SqlSharp 基于公开属性做 ORM 映射。属性是对象对外暴露的契约,字段是实现细节;普通字段不会作为实体列映射目标。

public sealed class Product
{
    public long Id { get; set; }

    public string Name { get; set; } = string.Empty;

    public decimal Price { get; set; }

    public DateTime CreatedAt { get; set; }
}

支持常见 CLR 标量类型、枚举、GuidDateTimeDateTimeOffsetTimeSpanDateOnlyTimeOnlybyte[] 等。复杂业务类型建议通过 ValueConverter 显式映射到数据库 provider 类型。

属性映射约定速查

场景 C# 属性 默认列名 主键识别 ValueGenerated
自增主键 public long id { get; set; } id OnAdd
普通属性 public string Name { get; set; } Name Never
Column 重命名 [Column("user_name")] public string Name { get; set; } user_name Never
Key 主键 [Key] public string Code { get; set; } Code Never
NotMapped 排除 [NotMapped] public string DisplayName { get; } 不映射 不适用
String id public string id { get; set; } id Never

约定自增只针对属性名为 id 且类型为整数的属性。Id 是否作为主键建议用 [Key] 或 Fluent API 显式声明,避免大小写约定差异带来误解。

DbContext 配置

DbContextOptionsBuilder 通过扩展对象保存配置,公开 API 保持精简。

方法 说明
UseConnectionFactory(Func<DbConnection>) 注册连接工厂。连接类型由业务项目的 ADO.NET 驱动提供
UseIdentitySql(string) 设置插入自增主键后读取 identity 的 SQL
UseIdentitySql(Func<IEntityType, string?>) 按实体类型动态生成 identity SQL
UseQueryTrackingBehavior(QueryTrackingBehavior) 设置默认查询跟踪行为
LogTo(Action<string, DbParameters>) 注册 SQL 日志回调
WithExtension<T>(T) 保存自定义扩展对象
Build() 构建 DbContextOptions
var options = new DbContextOptionsBuilder<AppDbContext>()
    .UseConnectionFactory(() => new MySqlConnection(connectionString))
    .UseIdentitySql("SELECT LAST_INSERT_ID()")
    .UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll)
    .LogTo((sql, parameters) =>
    {
        Console.WriteLine(sql);
        Console.WriteLine(parameters);
    })
    .Build();

也可以在 DbContext 中集中配置模型:

public sealed class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    public DbSet<Product> Products => Set<Product>();

    protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
    {
        configurationBuilder
            .Properties<Money>()
            .HaveConversion(new MoneyConverter());
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .ToTable("products")
            .HasKey(x => x.Id)
            .Property(x => x.Id, p => p.ValueGeneratedOnAdd());
    }
}

模型配置

DataAnnotations

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

[Table("sys_user")]
public sealed class AnnotatedUser
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    [Column("account")]
    public string Account { get; set; } = string.Empty;

    [ConcurrencyCheck]
    public int Version { get; set; }

    [NotMapped]
    public string DisplayName => Account;
}
注解 说明
[Table("name", Schema = "...")] 设置表名和可选 schema
[Column("name")] 设置列名
[Key] 标记主键
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 标记数据库生成值
[DatabaseGenerated(DatabaseGeneratedOption.None)] 关闭数据库生成值
[ConcurrencyCheck] 标记并发检查列
[NotMapped] 排除属性

Fluent API

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<ConfiguredUser>()
        .ToTable("sys_user")
        .HasKey(x => x.Id)
        .Property(x => x.Id, p => p.ValueGeneratedOnAdd())
        .Property(x => x.Account, p => p.HasColumnName("account"))
        .Property(x => x.Version, p => p.IsConcurrencyToken())
        .Ignore(x => x.DisplayName);
}

public sealed class ConfiguredUser
{
    public long Id { get; set; }

    public string Account { get; set; } = string.Empty;

    public int Version { get; set; }

    public string DisplayName => Account;
}

EntityTypeBuilder 方法

方法 说明
.ToTable(name, schema) 设置表名和可选 schema
.HasTableSharding(...) 配置实体的分表策略
.HasTableSuffixes(...) 使用后缀分表的便捷配置
.HasKey(...) 设置单主键或复合主键
.Property(...) 获取并配置属性
.Ignore(...) 排除属性

PropertyBuilder 方法

方法 说明
.HasColumnName(name) 设置列名
.ValueGeneratedNever() INSERT 时包含此列
.ValueGeneratedOnAdd() INSERT 后从数据库读取生成值
.IsConcurrencyToken() 标记为并发检查列
.HasConversion(...) 配置 ValueConverter
.HasJsonConversion<T>() 配置 JSON 文本转换

优先级规则

配置项 低到高优先级
表名 类型名 / DbSet 属性名 < [Table] < Fluent API .ToTable()
列名 属性名 < [Column] < Fluent API .HasColumnName()
主键 id 约定 / [Key] < Fluent API .HasKey()
值生成 id 整数约定 < [DatabaseGenerated] < Fluent API
排除属性 [NotMapped] 与 Fluent API .Ignore() 效果等同

每个 DbContext 类型拥有独立模型缓存,同一实体类型在不同上下文中可以有不同配置。

后缀分表

当分表由调用环境决定、后缀不属于实体数据时,可以配置有限的后缀集合:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<XxjPrice>()
        .ToTable("xxj_price")
        .HasTableSharding(sharding =>
            sharding.UseSuffixes("zj", "js"));
}

后缀分表也可以使用等价的便捷写法 .HasTableSuffixes("zj", "js")

使用 ForShard 创建绑定到指定物理表的 DbSet,查询和状态操作会共享该路由:

var zjPrices = db.Prices.ForShard("zj");

zjPrices.Add(price); // INSERT INTO xxj_price_zj

var rows = zjPrices
    .Where(x => x.ProductId == productId)
    .ToList();

后缀匹配不区分大小写,但生成的表名使用配置时的写法。未调用 ForShard、传入未配置后缀,或者尝试把同一个跟踪实体绑定到另一分表时,框架会抛出 InvalidOperationException。后缀只允许 ASCII 字母、数字和下划线。

Queryable 查询 API

DbSet<T> 继承 DbQueryable<T>,用于围绕实体元数据构建查询。它不是完整 IQueryable Provider,但提供字符串 SQL 片段和常用表达式重载。

基础查询

var found = db.Users.Find(1L);

var first = db.Users
    .OrderBy("Id")
    .First();

var maybe = db.Users
    .Where("account = @account")
    .Params(new { account = "admin" })
    .FirstOrDefault();

var all = db.Users.ToList();
方法 说明
Find(params object?[] keyValues) 按主键查找单行,未命中返回 null
First() 返回第一行,无结果抛异常
FirstOrDefault() 返回第一行,无结果返回 null
ToList() 返回列表
AsNoTracking() 查询结果不进入变更跟踪
Build() 返回当前 SQL 构建器和参数,用于调试或组合

字符串 SQL 查询

var page = db.Users
    .Where("account LIKE @keyword")
    .Params(new { keyword = "admin%" })
    .OrderBy("Id DESC")
    .ToPageResult(index: 1, size: 20);

var projection = db.Users
    .Select<UserListItem>("Id", "account AS Account")
    .ToList();
public sealed class UserListItem
{
    public long Id { get; set; }

    public string Account { get; set; } = string.Empty;
}
方法 说明
Where(sql, condition) 追加 WHERE 条件;多个条件自动用 AND 合并
OrderBy(sql, condition) 追加 ORDER BY 片段
GroupBy(sql, condition) 追加 GROUP BY 片段
Having(sql, condition) 追加 HAVING 条件
Select<TResult>(params string[] columns) 指定投影列并切换结果类型
Skip(offset) / Take(count) 跳过 / 限制行数
Page(index, count) 设置分页
ToPageResult(index, size) 返回 (Items, Total)

表达式查询

var activeUsers = db.Users
    .Where(x => x.Account == "admin")
    .OrderByDescending(x => x.Id)
    .ToList();

var projection = db.Users
    .Where(x => x.Account != null)
    .Select<UserListItem>(x => new UserListItem
    {
        Id = x.Id,
        Account = x.Account
    })
    .ToList();

表达式会在构建 SQL 时翻译,常量和闭包变量会自动参数化:

var minAge = 18;
var maxAge = 60;

var users = db.Users
    .Where(x => x.Age >= minAge)
    .Where(x => x.Age <= maxAge)
    .ToList();

支持的表达式能力:

能力 示例
比较 x.Age > 18x.Name == "Ada"
逻辑组合 x.Age > 18 && x.Account != null
NULL x.DeletedAt == nullx.DeletedAt != null
排序 .OrderBy(x => x.Age).OrderByDescending(x => x.Name)
分组 .GroupBy(x => new { x.Age, x.Version })
HAVING .Having(x => SqlFns.Count(x.Id) > 0)
投影 .Select<Dto>(x => new Dto { Name = x.Name })
聚合列 .Count(x => x.Id).Sum(x => x.Amount)

DbOps

DbOps 是表达式查询中的 SQL 辅助函数,只能出现在 SQL 表达式里。

var ids = new[] { 1L, 2L, 3L };

var users = db.Users
    .Alias("u")
    .Where(x =>
        DbOps.StartsWith(x.Account, "adm") &&
        DbOps.Contains(x.Name, "Admin") &&
        DbOps.In(x.Id, ids))
    .OrderBy(x => x.Account)
    .OrderByDescending(x => x.Id)
    .ToList();

var selected = db.Users
    .Where(x => DbOps.InSet(x.Id, "1, 2, 3"))
    .ToList();
方法 SQL 语义
DbOps.Contains(column, value) LIKE '%value%'
DbOps.StartsWith(column, value) LIKE 'value%'
DbOps.EndsWith(column, value) LIKE '%value'
DbOps.In(column, values) IN @values
DbOps.InSet(column, "1,2,3") 拆分文本集合并按属性类型转换
DbOps.InSub(column, subQuery) IN (subQuery)

DbFunctionAttribute

[DbFunction] 标记静态方法,可以在表达式查询中映射数据库函数。该特性只作用于方法,不作用于类。

using Soul.SqlSharp.Attributes;

public static class SqlFns
{
    [DbFunction("LOWER")]
    public static string Lower(string value)
    {
        throw new NotSupportedException();
    }

    [DbFunction("UPPER")]
    public static string Upper(string value)
    {
        throw new NotSupportedException();
    }

    [DbFunction("COUNT")]
    public static int Count<T>(T value)
    {
        throw new NotSupportedException();
    }

    [DbFunction("COUNT", Format = "*")]
    public static int CountAll()
    {
        throw new NotSupportedException();
    }

    [DbFunction("COUNT", Format = "DISTINCT {column}")]
    public static int CountDistinct<T>(T column)
    {
        throw new NotSupportedException();
    }
}
var rows = db.Users
    .GroupBy(x => x.Account)
    .Having(x => SqlFns.Count(x.Id) > 0)
    .Select<UserStat>(x => new UserStat
    {
        Account = x.Account,
        Count = SqlFns.Count(x.Id)
    })
    .ToList();
public sealed class UserStat
{
    public string Account { get; set; } = string.Empty;

    public int Count { get; set; }
}

未标记的普通 .NET 方法不会自动翻译成 SQL;这类方法会在构建 SQL 时抛出 NotSupportedException

聚合

var count = db.Users.Count("*");
var exists = db.Users.Any();
var totalAge = db.Users.Sum<int>("Age");
var avgAge = db.Users.Avg<decimal>("Age");
var maxId = db.Users.Max<long>("Id");
var minId = db.Users.Min<long>("Id");

var expressionCount = db.Users.Count(x => x.Id);

异步 API

常用查询和执行方法提供异步版本:

var users = await db.Users.ToListAsync(cancellationToken);
var total = await db.Users.CountAsync(cancellationToken);
var page = await db.Users.ToPageResultAsync(1, 20, cancellationToken);
var affected = await db.ExecuteAsync(sql, param, cancellationToken);

原生 SQL

原生 SQL 适合复杂查询、数据库特定语法和手写 SQL 优先的场景。

var users = db.Query<User>(
    "SELECT Id, account AS Account, Name FROM sys_user WHERE account = @account",
    new { account = "admin" });

var count = db.ExecuteScalar<long>(
    "SELECT COUNT(*) FROM sys_user WHERE account = @account",
    new { account = "admin" });

var affected = db.Execute(
    "UPDATE sys_user SET Name = @name WHERE Id = @id",
    new { id = 1L, name = "Ada" });

标量查询允许值类型:

var values = db.Query<int>("SELECT 42");
var total = db.ExecuteScalar<long>("SELECT COUNT(*) FROM sys_user");

DbParameters

DbParameters 是 SQL 参数容器,参数名可写 name@name:name?name,内部会统一归一化。

var parameters = new DbParameters();
parameters.Add("name", "Widget");
parameters.Add("price", 999m);

db.Execute(
    "UPDATE products SET Price = @price WHERE Name = @name",
    parameters);

也可以从对象或字典创建:

var fromObject = DbParameters.From(new { name = "Widget", price = 999m });

var fromDictionary = DbParameters.From(new Dictionary<string, object?>
{
    ["name"] = "Widget",
    ["price"] = 999m
});

DbParameters.From 会跳过明显的业务辅助复杂对象属性,并且最终只绑定 SQL 文本中真实出现的参数,避免把未使用的复杂对象误传给数据库驱动。

var query = db.Users
    .Params(new
    {
        account = "admin",
        Orders = new Dictionary<string, string>() // SQL 未引用时不会绑定
    })
    .Where("account = @account");

IN 参数支持集合展开:

var users = db.Users
    .Params(new { ids = new[] { 1L, 2L, 3L } })
    .Where("Id IN @ids")
    .ToList();

变更跟踪

默认查询会跟踪实体。只读查询可关闭跟踪:

var users = db.Users
    .AsNoTracking()
    .ToList();

实体状态:

状态 含义
Detached 未被 ChangeTracker 跟踪
Added 已调用 Add,待 INSERT
Unchanged 已持久化,无变化
Modified 已持久化,有属性变化,待 UPDATE
Deleted 已调用 Remove,待 DELETE

基本增删改:

var product = new Product
{
    Name = "Widget",
    Price = 999m,
    CreatedAt = DateTime.UtcNow
};

db.Products.Add(product);
db.SaveChanges();

product.Price = 1099m;
db.SaveChanges();

db.Products.Remove(product);
db.SaveChanges();

DbContext 或不先查询直接更新时,可以显式设置状态:

var detached = new Product
{
    Id = 10,
    Name = "New Name",
    Price = 100m
};

db.Products.Update(detached);
db.SaveChanges();

并发列通过 [ConcurrencyCheck].IsConcurrencyToken() 配置。UPDATE / DELETE 会把并发列原始值放入 WHERE 条件;实际影响行数为 0 时会抛出并发更新异常。

事务与连接生命周期

using var transaction = db.BeginTransaction();

db.Execute("UPDATE account SET Balance = Balance - @amount WHERE Id = @id", new { id = 1, amount = 100 });
db.Execute("UPDATE account SET Balance = Balance + @amount WHERE Id = @id", new { id = 2, amount = 100 });

transaction.Commit();

可以通过 HasTransaction() 判断当前上下文是否处于事务中:

if (db.HasTransaction())
{
    // 当前上下文已有事务
}

默认情况下,查询和执行会按需打开连接并在操作结束后释放。需要在非事务场景连续执行多次操作时,可以手动打开连接:

db.OpenConnection();
try
{
    db.Execute("UPDATE products SET Price = Price + 1");
    var products = db.Query<Product>("SELECT Id, Name, Price, CreatedAt FROM products");
}
finally
{
    db.CloseConnection();
}

事务进行中不要手动关闭连接。用户主动 OpenConnection() 后,后续操作会复用当前连接,直到 CloseConnection() 或释放 DbContext

ValueConverter

自定义业务类型 converter 配置在模型元数据上,不通过 TypeMapper.RegisterUseTypeMapper 这类运行时全局兜底入口。ValueConverter 是显式值转换扩展点。

using Soul.SqlSharp.Converters;

public readonly record struct Money(decimal Amount);

public sealed class MoneyConverter : ValueConverter<Money, decimal>
{
    public override decimal ConvertToProvider(Money value) => value.Amount;

    public override Money ConvertFromProvider(decimal value) => new Money(value);
}

属性级显式配置:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Order>()
        .Property(x => x.Total)
        .HasConversion<Money, decimal>(new MoneyConverter());
}

类型级默认约定:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<Money>()
        .HaveConversion(new MoneyConverter());
}

JSON 字段可以直接使用内置转换:

modelBuilder.Entity<Order>()
    .Property(x => x.Payload)
    .HasJsonConversion<OrderPayload>();

属性级配置优先于类型级约定。converter 会在实体物化、DbQueryable.Find 主键参数、DbQueryable.Params 参数绑定、表达式查询参数、SaveChanges 参数生成和变更跟踪存储值比较中生效。

没有属性元数据上下文的裸 SQL 参数和标量查询不会推断自定义业务类型 converter;这类场景应直接传 provider 值,或走实体 / Queryable 路径。

物化行为

实体、POCO 和标量物化统一由物化器处理。实体和 POCO 物化会生成专用委托,直接调用 DbDataReader.GetInt32GetInt64GetStringGetDecimal 等强类型读取方法,并直接写入属性 setter。

等价展开:

var entity = new User();

if (!reader.IsDBNull(0))
{
    entity.Id = reader.GetInt64(0);
}

if (!reader.IsDBNull(1))
{
    entity.Account = reader.GetString(1);
}

return entity;

如果数据库返回 NULL,物化器会跳过对应属性赋值,保留 CLR 默认值或属性初始化值。这个行为是为了保证 ORM 易用性,不会因为非 nullable 值类型字段遇到脏数据就直接中断整行物化。

标量查询不依赖列名,缓存键按目标类型、读取偏移和 provider 类型区分,避免把列名带入标量物化缓存。

许可证

MIT

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

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
1.0.0-beta.5 36 9/22/2026