Inkslab.DI 1.2.18

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

Inkslab

GitHub language codeSize AppVeyor AppVeyor tests GitHub issues

"Inkslab"是什么?

Inkslab 是一套简单、高效的轻量级框架,专注于现代化 C# 开发体验。框架采用模块化设计,提供统一的 API 接口,涵盖了对象映射、配置读取、序列化、依赖注入等核心功能。

🎯 核心特性

  • 统一API设计 - 所有模块遵循一致的设计原则和API风格
  • 语法糖扩展 - 基于扩展方法的语法糖,提升开发效率
  • 模块化架构 - 按需引用,最小化依赖
  • 自动启动机制 - XStartup 自动发现和注册组件
  • 多框架支持 - 支持 .NET Framework 4.6.1+、.NET Standard 2.1、.NET 6.0+

🚀 快速入门

安装

PM> Install-Package Inkslab

基础配置

using Inkslab;

// 框架自动启动(推荐)
using (var startup = new XStartup())
{
    startup.DoStartup();
}

📦 NuGet 包

Package NuGet Downloads 描述
Inkslab Inkslab Nuget 核心框架
Inkslab.Config Inkslab.Config Nuget 配置文件读取
Inkslab.Json Inkslab.Json Nuget JSON 序列化
Inkslab.Map Inkslab.Map Nuget 对象映射
Inkslab.DI Inkslab.DI Nuget 依赖注入扩展
Inkslab.Net Inkslab.Net Nuget HTTP 请求组件

🏗️ 核心技术架构

1. 扩展方法体系

Inkslab 基于 C# 扩展方法构建了一套完整的语法糖体系,位于 src/Inkslab/Extentions/ 目录:

字符串扩展 (StringExtensions)
// 命名规范转换
string camelCase = "UserName".ToCamelCase();        // → "userName"
string snakeCase = "UserName".ToSnakeCase();        // → "user_name"  
string pascalCase = "user_name".ToPascalCase();     // → "UserName"
string kebabCase = "UserName".ToKebabCase();        // → "user-name"

// 统一命名转换API
string result = "UserName".ToNamingCase(NamingType.SnakeCase); // → "user_name"

// 配置读取语法糖
string dbConnection = "ConnectionStrings:Default".Config<string>();
var appSettings = "AppSettings".Config<AppConfig>();
集合扩展 (IEnumerableExtentions)
/// <summary>
/// 内容对齐。
/// </summary>
public void AlignTest()
{
    var array1 = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
    var array2 = new List<int> { 4, 5, 1, 2, 3, 6, 7 };

    //? 将 array2 按照 array1 的集合排序。
    var array3 = array2
        .AlignOverall(array1)
        .ToList();

    //? 比较两个集合相同下标位,值是否相同。
    array3.ZipEach(array1, Assert.Equal);
}

/// <summary>
/// 内容遍历。
/// </summary>
public void JoinEachTest()
{
    var array1 = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
    var array2 = new List<DistinctA>();

    var r = new Random();

    for (int i = 0, len = 50; i < len; i++)
    {
        array2.Add(new DistinctA
        {
            Id = r.Next(len),
            Name = i.ToString(),
            Date = DateTime.Now
        });
    }
    //? 与 Join 逻辑相同,但不需要返回新的集合。
    array1.JoinEach(array2, x => x, y => y.Id, (x, y) =>
    {
        Assert.Equal(x, y.Id);
    });
}
加密扩展 (CryptoExtensions)
// 常用哈希算法
string md5 = "password".Md5();
string encrypt = "data".Encrypt("Test@*$!", CryptoKind.DES); // 加密
string decrypt = "data".Decrypt("Test@*$!", CryptoKind.DES); // 解密
日期时间扩展 (DateTimeExtensions)
自动根据提供时间是Utc / Local 自动处理一周的第一天和最后一天。
  • Utc:周日为一周的第一天;周六为一周的最后一天。
  • Local:周一为一周的第一天;周日为一周的最后一天。

2. 序列化框架

JSON 序列化 (基于 Newtonsoft.Json)

核心实现:DefaultJsonHelper

// 基础用法
string json = JsonHelper.ToJson(obj);
T result = JsonHelper.Json<T>(json);

// 命名规范支持
string json = JsonHelper.ToJson(obj, NamingType.CamelCase);
var result = JsonHelper.Json<User>(json, NamingType.SnakeCase);

// 格式化输出
string prettyJson = JsonHelper.ToJson(obj, indented: true);
自定义JSON序列化器
public class CustomJsonHelper : IJsonHelper
{
    public string ToJson<T>(T jsonObj, NamingType namingType = NamingType.Normal, bool indented = false)
    {
        // 自定义序列化逻辑
        var settings = new JsonSerializerSettings();
        
        // 根据命名规范配置
        switch (namingType)
        {
            case NamingType.CamelCase:
                settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                break;
            case NamingType.SnakeCase:
                settings.ContractResolver = new DefaultContractResolver 
                { 
                    NamingStrategy = new SnakeCaseNamingStrategy() 
                };
                break;
        }
        
        return JsonConvert.SerializeObject(jsonObj, indented ? Formatting.Indented : Formatting.None, settings);
    }
    
    public T Json<T>(string json, NamingType namingType = NamingType.Normal)
    {
        // 自定义反序列化逻辑
    }
}

// 注册自定义实现
SingletonPools.TryAdd<IJsonHelper, CustomJsonHelper>();

3. 语法糖适配器 (AdapterSugar)

Inkslab 框架通过 AdapterSugar<T> 实现了自动化的语法糖适配机制,极大提升了扩展性和运行时性能。其核心流程如下:

1. 类型与成员信息初始化
  • 自动获取泛型参数 T 及正则相关类型(如 MatchGroupCapture 等)的反射信息。
  • 构建表达式树所需的参数表达式。
2. 方法发现与遍历
  • 自动发现 T 类型下所有公开实例方法。
  • 仅处理参数数量大于0且返回类型为 string 的方法。
3. 参数分析与表达式构建
  • 支持参数类型:MatchGroupCollectionGroupCaptureCollectionCapturestringbool
  • 根据参数类型,自动生成变量声明、赋值、条件判断及参数列表。
  • 不支持类型将抛出异常,确保类型安全。
4. 条件与特性处理
  • 支持 MatchAttribute 指定正则分组名。
  • 支持 MismatchAttribute 补充不匹配条件。
  • 汇总所有条件表达式,生成最终的匹配条件。
5. 表达式树编译
  • 条件表达式编译为 Func<Match, bool>,用于判断当前正则匹配是否适用该方法。
  • 方法调用表达式编译为 Func<T, Match, string>,用于执行实际转换逻辑。
6. 适配器缓存
  • 每个方法生成一个适配器(包含条件判断与转换逻辑),自动缓存到静态列表,供后续格式化调用时高效匹配和执行。
public abstract class AdapterSugar<T> : ISugar where T : AdapterSugar<T>, ISugar
{
    // 适配器模式实现
    private class Adapter
    {
        public Func<Match, bool> CanConvert { get; set; }
        public Func<T, Match, string> Convert { get; set; }
    }
    
    // 撤销操作
    public bool Undo { get; private set; }
    
    // 格式化方法
    public string Format(Match match);
}
自定义语法糖示例
  public class StringSugar : AdapterSugar<StringSugar>
  {
      private readonly object _source;
      private readonly DefaultSettings _settings;
      private readonly SyntaxPool _syntaxPool;

      public StringSugar(object source, DefaultSettings settings, SyntaxPool syntaxPool)
      {
          _source = source ?? throw new ArgumentNullException(nameof(source));
          _settings = settings ?? throw new ArgumentNullException(nameof(settings));
          _syntaxPool = syntaxPool ?? throw new ArgumentNullException(nameof(syntaxPool));
      }

      [Mismatch("token")] //? 不匹配 token。
      public string Single(string name, string format) => _syntaxPool.GetValue(this, _source, _settings, name, format);

      [Mismatch("token")] //? 不匹配 token。
      public string Single(string name) => _syntaxPool.GetValue(this, _source, _settings, name);

      public string Combination(string pre, string token, string name, string format) => _syntaxPool.GetValue(this, _source, _settings, pre, token, name, format);

      public string Combination(string pre, string token, string name) => _syntaxPool.GetValue(this, _source, _settings, pre, token, name);
  }

4. 单例池管理 (SingletonPools)

// 注册单例
SingletonPools.TryAdd<IService, ServiceImpl>();
SingletonPools.TryAdd(new ServiceInstance());

// 获取单例
var service = SingletonPools.Singleton<IService>();

💡 核心功能详解

配置管理

// 强类型配置
public class DatabaseConfig
{
    public string ConnectionString { get; set; }
    public int Timeout { get; set; }
}

var dbConfig = "Database".Config<DatabaseConfig>();

// 配置监听(热更新)
var options = "Database".Options<DatabaseConfig>();
// options.Value 会随配置文件变化自动更新

对象映射

// 基础映射
var dto = Mapper.Map<UserDto>(user);

主键生成

// 雪花算法ID生成
long id = KeyGen.Id();
Key newKey = KeyGen.New();

// 自定义机房和机器号
SingletonPools.TryAdd(new KeyOptions(workerId: 1, datacenterId: 1));

命名规范转换

基于 NamingType 枚举的统一命名处理:

public enum NamingType
{
    Normal = 0,      // 原样输出
    CamelCase = 1,   // 驼峰:userName
    SnakeCase = 2,   // 蛇形:user_name  
    PascalCase = 3,  // 帕斯卡:UserName
    KebabCase = 4    // 短横线:user-name
}

// 使用示例
string result = "UserName".ToNamingCase(NamingType.SnakeCase);

🎓 高级应用指南

1. 自定义启动器

实现 IStartup 接口创建自定义启动器:

public class CustomStartup : IStartup
{
    public int Code => 999;      // 启动代码(用于排序)
    public int Weight => 1;      // 权重

    public void Startup()
    {
        // 自定义初始化逻辑
        SingletonPools.TryAdd<ICustomService, CustomServiceImpl>();
        
        // 注册语法糖
        RegisterCustomSyntaxSugar();
        
        // 配置全局设置
        ConfigureGlobalSettings();
    }
}

2. 扩展方法最佳实践

#pragma warning disable IDE0130 // 命名空间与文件夹结构不匹配
namespace System // 扩展到系统命名空间,全局可用
#pragma warning restore IDE0130

{
    public static class CustomExtensions
    {
        /// <summary>
        /// 安全的字符串截取
        /// </summary>
        public static string SafeSubstring(this string source, int startIndex, int length)
        {
            if (string.IsNullOrEmpty(source) || startIndex >= source.Length)
                return string.Empty;
                
            return source.Substring(startIndex, Math.Min(length, source.Length - startIndex));
        }
        
        /// <summary>
        /// 条件执行扩展
        /// </summary>
        public static T If<T>(this T source, bool condition, Func<T, T> action)
        {
            return condition ? action(source) : source;
        }
    }
}

3. 高性能序列化配置

public class HighPerformanceJsonHelper : IJsonHelper
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        // 性能优化配置
        DateTimeZoneHandling = DateTimeZoneHandling.Utc,
        NullValueHandling = NullValueHandling.Ignore,
        DefaultValueHandling = DefaultValueHandling.Ignore,
        
        // 类型处理
        TypeNameHandling = TypeNameHandling.None,
        
        // 错误处理
        Error = (sender, args) => 
        {
            // 记录序列化错误但不中断处理
            args.ErrorContext.Handled = true;
        }
    };
    
    public string ToJson<T>(T jsonObj, NamingType namingType = NamingType.Normal, bool indented = false)
    {
        var settings = Settings.Clone();
        settings.ContractResolver = GetContractResolver(namingType);
        settings.Formatting = indented ? Formatting.Indented : Formatting.None;
        
        return JsonConvert.SerializeObject(jsonObj, settings);
    }
    
    private static IContractResolver GetContractResolver(NamingType namingType)
    {
        // 缓存 ContractResolver 实例以提升性能
        return namingType switch
        {
            NamingType.CamelCase => CachedResolvers.CamelCase,
            NamingType.SnakeCase => CachedResolvers.SnakeCase,
            NamingType.PascalCase => CachedResolvers.PascalCase,
            NamingType.KebabCase => CachedResolvers.KebabCase,
            _ => CachedResolvers.Default
        };
    }
    
    private static class CachedResolvers
    {
        public static readonly IContractResolver Default = new DefaultContractResolver();
        public static readonly IContractResolver CamelCase = new CamelCasePropertyNamesContractResolver();
        public static readonly IContractResolver SnakeCase = new DefaultContractResolver 
        { 
            NamingStrategy = new SnakeCaseNamingStrategy() 
        };
        // ... 其他缓存的解析器
    }
}

4. 模块化架构设计

// 模块接口定义
public interface IModule
{
    string Name { get; }
    Version Version { get; }
    void Initialize();
    void Dispose();
}

// 模块管理器
public class ModuleManager
{
    private readonly List<IModule> _modules = new();
    
    public void LoadModule<T>() where T : IModule, new()
    {
        var module = new T();
        module.Initialize();
        _modules.Add(module);
    }
    
    public void LoadModules(Assembly assembly)
    {
        var moduleTypes = assembly.GetTypes()
            .Where(t => typeof(IModule).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
            
        foreach (var type in moduleTypes)
        {
            var module = (IModule)Activator.CreateInstance(type);
            module.Initialize();
            _modules.Add(module);
        }
    }
}

// 在启动器中使用
public class ModularStartup : IStartup
{
    public int Code => 100;
    public int Weight => 1;
    
    public void Startup()
    {
        var moduleManager = new ModuleManager();
        
        // 加载核心模块
        moduleManager.LoadModule<ConfigModule>();
        moduleManager.LoadModule<JsonModule>();
        moduleManager.LoadModule<MappingModule>();
        
        // 自动发现并加载模块
        var assemblies = AssemblyFinder.FindAssemblies("*.Module.dll");
        foreach (var assembly in assemblies)
        {
            moduleManager.LoadModules(assembly);
        }
        
        SingletonPools.TryAdd<ModuleManager>(moduleManager);
    }
}

5. 性能监控和诊断

public static class PerformanceExtensions
{
    public static T WithTiming<T>(this Func<T> func, Action<TimeSpan> onCompleted)
    {
        var stopwatch = Stopwatch.StartNew();
        try
        {
            return func();
        }
        finally
        {
            stopwatch.Stop();
            onCompleted(stopwatch.Elapsed);
        }
    }
    
    public static async Task<T> WithTimingAsync<T>(this Func<Task<T>> func, Action<TimeSpan> onCompleted)
    {
        var stopwatch = Stopwatch.StartNew();
        try
        {
            return await func();
        }
        finally
        {
            stopwatch.Stop();
            onCompleted(stopwatch.Elapsed);
        }
    }
}

// 使用示例
var result = (() => ExpensiveOperation()).WithTiming(elapsed => 
{
    if (elapsed.TotalMilliseconds > 1000)
    {
        Logger.LogWarning($"Slow operation detected: {elapsed.TotalMilliseconds}ms");
    }
});

🔧 测试和调试

框架提供了完整的单元测试,位于 tests/ 目录:

示例测试用例

参考 StringExtensionsTests 了解如何编写测试:

[Theory]
[InlineData("namingCase", NamingType.Normal, "namingCase")]
[InlineData("NamingCase", NamingType.CamelCase, "namingCase")]  
[InlineData("naming_case", NamingType.PascalCase, "NamingCase")]
[InlineData("UserName", NamingType.SnakeCase, "user_name")]
public void NamingConversionTest(string input, NamingType namingType, string expected)
{
    var result = input.ToNamingCase(namingType);
    Assert.Equal(expected, result);
}

📈 性能建议

  1. 合理使用单例池 - 避免频繁创建重型对象
  2. 缓存序列化配置 - JsonSerializerSettings 等配置对象应该缓存
  3. 批量操作 - 使用框架提供的批量扩展方法
  4. 异步优先 - 在 I/O 密集型操作中优先使用异步方法
  5. 监控内存使用 - 定期检查大对象和集合的内存占用

🤝 贡献指南

  1. Fork 项目
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 打开 Pull Request

📝 许可证

本项目基于 MIT 许可证 - 查看 LICENSE 文件了解详情。


Stargazers over time

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  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 was computed.  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 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
.NET Framework net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Inkslab.DI:

Package Downloads
xunitPlus

Automatic injection of constructor parameters.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.18 191 10/9/2025
1.2.17 183 8/15/2025
1.2.16 152 6/7/2025
1.2.15 190 5/28/2025
1.2.14 276 11/22/2024
1.2.13 717 9/10/2024
1.2.12 179 9/10/2024
1.2.11 284 8/4/2024
1.2.10 161 7/29/2024
1.2.9 142 7/29/2024
1.2.8.5 3,391 5/15/2024
1.2.8.2 195 4/29/2024
1.2.8.1 198 4/29/2024 1.2.8.1 is deprecated because it has critical bugs.
1.2.8 2,273 3/26/2024
1.2.7 247 3/1/2024
1.2.5 554 1/2/2024
1.2.4.1 317 12/20/2023
1.2.4 243 12/12/2023
1.2.3 182 12/12/2023
1.2.2 172 12/12/2023
1.2.1.15 291 11/22/2023
1.2.1.14 529 11/8/2023
1.2.1.13 279 11/3/2023
1.2.1.12 307 11/1/2023
1.2.1.11 230 10/25/2023
1.2.1.10 186 10/24/2023
1.2.1.9 195 10/22/2023
1.2.1.8 192 10/16/2023
1.2.1.7 240 10/12/2023
1.2.1.6 231 10/9/2023
1.2.1.4 266 7/14/2023
1.2.1.3 245 7/14/2023
1.2.1.1 225 7/12/2023
1.2.1 240 7/10/2023
1.2.0 254 7/9/2023
1.1.0 235 7/9/2023
1.0.2.9 430 4/21/2023
1.0.2.8 273 4/21/2023
1.0.2.7 327 3/30/2023
1.0.2.5 395 2/23/2023
1.0.2.1 337 2/7/2023
1.0.2 391 2/3/2023
1.0.1 473 12/20/2022
1.0.0 427 12/13/2022