Wjybxx.Commons.Core 1.1.0-rc2

This is a prerelease version of Wjybxx.Commons.Core.
There is a newer version of this package available.
See the version list below for details.
dotnet add package Wjybxx.Commons.Core --version 1.1.0-rc2                
NuGet\Install-Package Wjybxx.Commons.Core -Version 1.1.0-rc2                
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="Wjybxx.Commons.Core" Version="1.1.0-rc2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Wjybxx.Commons.Core --version 1.1.0-rc2                
#r "nuget: Wjybxx.Commons.Core, 1.1.0-rc2"                
#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.
// Install Wjybxx.Commons.Core as a Cake Addin
#addin nuget:?package=Wjybxx.Commons.Core&version=1.1.0-rc2&prerelease

// Install Wjybxx.Commons.Core as a Cake Tool
#tool nuget:?package=Wjybxx.Commons.Core&version=1.1.0-rc2&prerelease                

csharp-commons

csharp公共库,包含集合等基础组件;nuget搜索'wjybxx'即可查看到相关库。

注意: 1.0.x 尚属于快速迭代版本,等基础工具基本完备的时候,会更新到 1.1.x 版本。因为我还有几个项目没有完成,会把遇见的一些基础工具迁移到这里,或在这里实现。

命名规则

由于我频繁在Java和C#之间切换,因此统一的命名规则对我来说很必要,但这可能让仅写C#的开发者不适应。具体的命名规则可见:C#命名规范


Collections

但凡C#的基础集合库好用一点,我也不至于自己造轮子,实现的集合类:

  1. LinkedDictionary 保持插入顺序的字典,并提供大量的有用方法。
  2. LinkedHashSet 保持插入顺序的Set,并提供大量的有用方法。
  3. IndexedPriorityQueue 含索引的优先级队列,高查询和删除效率。
  4. BoundedArrayDeque 基于数组的有界双端队列,允许手动调整容量。
  5. MultiChunkDeque 分块无界双端队列。

LinkedDictionary特殊接口示例:


    public class LinkedDictionary<TKey,TValue> {
        TKey PeekFirstKey();
        TKey PeekLastKey();
        void AddFirst(TKey key, TValue value);
        void AddLast(TKey key, TValue value);
        KeyValuePair<TKey, TValue> RemoveFirst();
        KeyValuePair<TKey, TValue> RemoveLast();
        TValue GetAndMoveToFirst(TKey key);        
        TValue GetAndMoveToLast(TKey key);
    }
    

LinkedDictionary采用线性探测法解决hash冲突,通过在GetNode方法中记录线性探测次数,统计查询数据如下:

  1. 1W个int类型key,查询所有key,线性探测总次数 4000~5000, 平均值小于1
  2. 10W个int类型key,查询所有key,线性探测总次数 11000~12000,平均值小于1
  3. 1W个string类型key,长度24,查询所有key,线性探测总次数 4000~5000,平均值小于1 -- 与int相似,且调整长度几无变化。
  4. 10W个string类型key,长度24,查询所有key,线性探测总次数 11000~12000,平均值小于1 -- 与int相似,且调整长度几无变化。

APT包

APT包是javapoet仓库的移植版。 我在java端使用javapoet生成各类辅助类已有5年左右,这是个非常好用的轮子的,但C#端没有合适的等价物,于是自己移植了一版。

用言语描述javapoet不够直观,我们直接看代码生成器和生成的代码(可运行测试用例)(代码生成器的最佳示例可见Dson和BTree库)。

GeneratorTest测试类(生成器)代码如下:

    private static TypeSpec BuildClassType() {
        TypeName dictionaryTypeName = TypeName.Get(typeof(LinkedDictionary<string, object>));
        AttributeSpec processorAttribute = AttributeSpec.NewBuilder(ClassName.Get(typeof(GeneratedAttribute)))
            .Constructor(CodeBlock.Of("$S", "GeneratorTest")) // 字符串$S
            .Build();

        AttributeSpec attributeSpec = AttributeSpec.NewBuilder(ClassName.Get(typeof(MyCodeAttribute)))
            .AddMember("Name", CodeBlock.Of("$S", "wjybxx"))
            .AddMember("Age", CodeBlock.Of("29"))
            .Build();

        TypeSpec classType = TypeSpec.NewClassBuilder("ClassBean")
            .AddModifiers(Modifiers.Public)
            .AddAttribute(processorAttribute)
            .AddAttribute(attributeSpec)
            // 字段
            .AddField(TypeName.INT, "age", Modifiers.Private)
            .AddField(TypeName.STRING, "name", Modifiers.Private)
            .AddSpec(FieldSpec.NewBuilder(dictionaryTypeName, "blackboard", Modifiers.Public | Modifiers.Readonly)
                .Initializer("new $T()", dictionaryTypeName)
                .Build())
            // 构造函数
            .AddSpec(MethodSpec.NewConstructorBuilder()
                .AddModifiers(Modifiers.Public)
                .ConstructorInvoker(CodeBlock.Of("this($L, $S)", 29, "wjybxx"))
                .Build())
            .AddSpec(MethodSpec.NewConstructorBuilder()
                .AddModifiers(Modifiers.Public)
                .AddParameter(TypeName.INT, "age")
                .AddParameter(TypeName.STRING, "name")
                .Code(CodeBlock.NewBuilder()
                    .AddStatement("this.age = age")
                    .AddStatement("this.name = name")
                    .Build())
                .Build())
            // 属性
            .AddSpec(PropertySpec.NewBuilder(TypeName.INT, "Age", Modifiers.Public)
                .Getter(CodeBlock.Of("age").WithExpressionStyle(true))
                .Setter(CodeBlock.Of("age = value").WithExpressionStyle(true))
                .Build())
            .AddSpec(PropertySpec.NewBuilder(TypeName.BOOL, "IsOnline", Modifiers.Private)
                .Initializer("$L", false)
                .Build()
            )
            // 普通方法
            .AddSpec(MethodSpec.NewMethodBuilder("Sum")
                .AddDocument("求int的和")
                .AddModifiers(Modifiers.Public)
                .Returns(TypeName.INT)
                .AddParameter(TypeName.INT, "a")
                .AddParameter(TypeName.INT, "b")
                .Code(CodeBlock.NewBuilder()
                    .AddStatement("return a + b")
                    .Build())
                .Build())
            .AddSpec(MethodSpec.NewMethodBuilder("SumNullable")
                .AddDocument("求空int的和")
                .AddModifiers(Modifiers.Public | Modifiers.Extern)
                .Returns(TypeName.INT.MakeNullableType())
                .AddParameter(TypeName.INT.MakeNullableType(), "a")
                .AddParameter(TypeName.INT, "b")
                .Build())
            .AddSpec(MethodSpec.NewMethodBuilder("SumRef")
                .AddDocument("求ref int的和")
                .AddModifiers(Modifiers.Public | Modifiers.Extern)
                .Returns(TypeName.INT)
                .AddParameter(TypeName.INT.MakeByRefType(), "a")
                .AddParameter(TypeName.INT.MakeByRefType(ByRefTypeName.Kind.In), "b")
                .Build())
            .Build();
        return classType;
    }

下面是测试GeneratorTest类生成的代码:

    using Wjybxx.Commons.Attributes;
    using Commons.Tests.Apt;
    using Wjybxx.Commons.Collections;
    
    namespace Wjybxx.Commons.Apt;
    
    [Generated("GeneratorTest")]
    [MyCode(Name = "wjybxx", Age = 29)]
    public class ClassBean 
    {
      private int age;
      private string name;
      public readonly LinkedDictionary<string, object> blackboard = new LinkedDictionary<string, object>();
    
      public ClassBean()
       : this(29, "wjybxx") {
      }
    
      public ClassBean(int age, string name) {
        this.age = age;
        this.name = name;
      }
    
      public int Age {
        get => age;
        set => age = value;
      }
    
      private bool IsOnline { get; set; } = false;
    
      /// <summary>
      /// 求int的和
      /// </summary>
      public int Sum(int a, int b) {
        return a + b;
      }
    
      /// <summary>
      /// 求空int的和
      /// </summary>
      public extern int? SumNullable(int? a, int b);
    
      /// <summary>
      /// 求ref int的和
      /// </summary>
      public extern int SumRef(ref int a, in int b);
    }

Concurrent包

  1. 提供了Java的Executor和Future框架,并提供了对应的await语法支持。
  2. 提供了默认的EventLoop实现。

PS:c#端不打算再实现Disruptor库。

await语法的讨论

C#的Concurrent包,个人用得非常难受。究其原因:上下文(sync/execution)的传递是隐式的。这导致我们对线程和任务上下文的控制力度较弱,部分功能编写起来十分难受。
以我的使用经验来看,C#的await/async语法会导致这样的结果:使简单的问题更简单,使复杂的问题更复杂

多线程编程从来都不是个简单问题,单线程语言的await/async不涉及复杂的线程和上下文切换问题,因此使用起来简单; 在多线程下,存在上下文和线程的控制问题,按照单线程语言async/await语法进行设计,只是让代码看起来简单了,实际上不论是语言的开发者,还是语言的使用者,面临的问题都更多了。

个人认为, 多线程下的await最佳实现应当允许传参,允许指定await后续操作的线程,以及其它调度选项。

    await future executor;    
    await future executor options;

个人公众号(游戏开发)

写代码的诗人

ReleaseNotes

1.0.15

  1. APT库相关支持(部分工具方法)
  2. 集合的默认迭代器修改为结构体类型,并对外开放
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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.
  • net7.0

    • No dependencies.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on Wjybxx.Commons.Core:

Package Downloads
Wjybxx.Dson

Dson-有点奇怪的配置文件格式和序列化方案

Wjybxx.Commons.Concurrent

并发基础库;提供事件循环和基于事件循环的await语法

Wjybxx.Commons.Apt

注解处理器工具,结构化代码生成工具

Wjybxx.BTree.Core

BTree-非典型的高性能行为树实现

Wjybxx.Dson.Core

Dson-有点奇怪的配置文件格式和序列化方案

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.1 91 11/6/2024
1.2.0 179 10/28/2024
1.1.1 503 8/25/2024
1.1.0 319 8/21/2024
1.1.0-rc3 134 7/31/2024
1.1.0-rc2 165 7/21/2024
1.1.0-rc1 174 7/14/2024
1.0.15 188 6/29/2024
1.0.14 109 5/22/2024
1.0.13 174 5/12/2024
1.0.12 168 4/11/2024
1.0.11 144 4/9/2024
1.0.10 125 4/8/2024
1.0.9 140 4/3/2024
1.0.8 140 3/18/2024
1.0.7 186 1/7/2024
1.0.6 149 1/6/2024
1.0.5 101 1/4/2024
1.0.4 136 1/2/2024
1.0.3 126 1/1/2024
1.0.2 234 12/26/2023
1.0.1 153 12/24/2023
1.0.0 174 12/23/2023
1.0.0-alpha 139 12/23/2023