RSCG – ConstructorGenerator

RSCG – ConstructorGenerator
 
 

name ConstructorGenerator
nuget https://www.nuget.org/packages/ConstructorGenerator/
link https://github.com/Swarley97/ConstructorGenerator
author Swarley97

Generate constructor for classes

 

This is how you can use ConstructorGenerator .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
 
    <ItemGroup>
      <PackageReference Include="ConstructorGenerator" Version="1.0.2" />
    </ItemGroup>
</Project>

The code that you will use is

1
2
3
4
5
using QuickConstructorDemo;
 
var p = new Person("Andrei", "Ignat");
 
Console.WriteLine(p.FullName());
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
using ConstructorGenerator.Attributes;
 
namespace QuickConstructorDemo;
 
[GenerateFullConstructor]
internal partial class Person
{
    [ConstructorDependency]
    private readonly string FirstName="";
 
    private readonly string? LastName;
     
    public string FullName() => $"{FirstName} {LastName}";
     
}

 

The code that is generated is

01
02
03
04
05
06
07
08
09
10
11
12
13
namespace QuickConstructorDemo
{
    internal partial class Person
    {
        public Person(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
            OnConstructing();
        }
        partial void OnConstructing();
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/ConstructorGenerator

RSCG – Valuify

RSCG – Valuify
 
 

name Valuify
nuget https://www.nuget.org/packages/Valuify/
link https://github.com/MooVC/valuify
author Paul Martins

Generating Equals from properties

 

This is how you can use Valuify .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
  <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Valuify" Version="1.1.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
 
  
</Project>

The code that you will use is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// See https://aka.ms/new-console-template for more information
using GeneratorEqualsDemo;
var p1 = new Person()
{
    ID = 1,
    FirstName = "Andrei",
    LastName = "Ignat"
};
var p2= new Person()
{
    ID = 1,
    FirstName = "Andrei",
    LastName = "Ignat"
};
Console.WriteLine(p1==p2);
01
02
03
04
05
06
07
08
09
10
namespace GeneratorEqualsDemo;
 
[Valuify.Valuify]
partial class Person
{
    public int ID { get; set; }
    public string? FirstName { get; set; }
   
    public string? LastName { get; set; }
}

 

The code that is generated is

01
02
03
04
05
06
07
08
09
10
11
namespace Valuify
{
    using System;
    using System.Diagnostics.CodeAnalysis;
 
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    internal sealed class ValuifyAttribute
        : Attribute
    {
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
    {
        public static bool operator ==(Person left, Person right)
        {
            if (ReferenceEquals(left, right))
            {
                return true;
            }
 
            if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
            {
                return false;
            }
 
            return global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(left.ID, right.ID)
                && global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(left.FirstName, right.FirstName)
                && global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(left.LastName, right.LastName);
        }
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
    {
        public sealed override bool Equals(object other)
        {
            return Equals(other as Person);
        }
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
    {
        public sealed override int GetHashCode()
        {
            return global::Valuify.Internal.HashCode.Combine(ID, FirstName, LastName);
        }
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
    {
        public bool Equals(Person other)
        {
            return this == other;
        }
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
        : IEquatable<Person>
    {
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
    {
        public static bool operator !=(Person left, Person right)
        {
            return !(left == right);
        }
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
namespace GeneratorEqualsDemo
{
    using System;
    using System.Collections.Generic;
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable disable
    #endif
 
    partial class Person
    {
        public sealed override string ToString()
        {
            return string.Format("Person { ID = {0}, FirstName = {1}, LastName = {2} }", ID, FirstName, LastName);
        }
    }
 
    #if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
    #nullable restore
    #endif
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace Valuify.Internal
{
    using System;
    using System.Collections;
 
    internal static class HashCode
    {
        private const int HashSeed = 0x1505;
        private const int HashPrime = -1521134295;
 
        public static int Combine(params object[] values)
        {
            int hash = HashSeed;
 
            foreach (object value in values)
            {
                if (value is IEnumerable && !(value is string))
                {
                    IEnumerable enumerable = (IEnumerable)value;
 
                    foreach (object element in enumerable)
                    {
                        hash = PerformCombine(hash, element);
                    }
                }
                else
                {
                    hash = PerformCombine(hash, value);
                }
            }
 
            return hash;
        }
 
        private static int PerformCombine(int hash, object value)
        {
            int other = GetHashCode(value);
 
            unchecked
            {
                return (other * HashPrime) + hash;
            }
        }
 
        private static int GetHashCode(object value)
        {
            int code = 0;
 
            if (value != null)
            {
                code = value.GetHashCode();
            }
 
            return code;
        }
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
namespace Valuify.Internal
{
    using System;
    using System.Collections;
 
    internal sealed class SequenceEqualityComparer
    {
        public static readonly SequenceEqualityComparer Default = new SequenceEqualityComparer();
 
        public bool Equals(IEnumerable left, IEnumerable right)
        {
            if (ReferenceEquals(left, right))
            {
                return true;
            }
 
            if (ReferenceEquals(left, null) || ReferenceEquals(null, right))
            {
                return false;
            }
 
            return Equals(left.GetEnumerator(), right.GetEnumerator());
        }
 
        public int GetHashCode(IEnumerable enumerable)
        {
            return HashCode.Combine(enumerable);
        }
 
        private static bool Equals(IEnumerator left, IEnumerator right)
        {
            while (left.MoveNext())
            {
                if (!right.MoveNext())
                {
                    return false;
                }
 
                if (!Equals(left.Current, right.Current))
                {
                    return false;
                }
            }
 
            return !right.MoveNext();
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Valuify

RSCG – Equatable.Generator

RSCG – Equatable.Generator
 
 

name Equatable.Generator
nuget https://www.nuget.org/packages/Equatable.Generator/
link https://github.com/loresoft/Equatable.Generator
author Eden Prairie

Generating Equals from properties

 

This is how you can use Equatable.Generator .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
  <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Equatable.Generator" Version="2.0.0" />
  </ItemGroup>
</Project>

The code that you will use is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// See https://aka.ms/new-console-template for more information
using GeneratorEqualsDemo;
var p1 = new Person()
{
    ID = 1,
    FirstName = "Andrei",
    LastName = "Ignat"
};
var p2= new Person()
{
    ID = 2,
    FirstName = "aNdrei",
    LastName = "Ignat"
};
Console.WriteLine(p1==p2);
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
using Equatable.Attributes;
 
namespace GeneratorEqualsDemo;
 
[Equatable]
partial class Person
{
    [IgnoreEquality]
    public int ID { get; set; }
    [StringEquality(StringComparison.OrdinalIgnoreCase)]
    public string? FirstName { get; set; }
    [StringEquality(StringComparison.OrdinalIgnoreCase)]
 
    public string? LastName { get; set; }
}

 

The code that is generated is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// <auto-generated />
#nullable enable
 
namespace GeneratorEqualsDemo
{
    partial class Person : global::System.IEquatable<global::GeneratorEqualsDemo.Person?>
    {
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Equatable.SourceGenerator", "2.0.0+10ad4b045a688eb10980afcd11ddb8e64505eda6")]
        public bool Equals(global::GeneratorEqualsDemo.Person? other)
        {
            return !(other is null)
                && global::System.StringComparer.OrdinalIgnoreCase.Equals(FirstName, other.FirstName)
                && global::System.StringComparer.OrdinalIgnoreCase.Equals(LastName, other.LastName);
 
        }
 
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Equatable.SourceGenerator", "2.0.0+10ad4b045a688eb10980afcd11ddb8e64505eda6")]
        public override bool Equals(object? obj)
        {
            return Equals(obj as global::GeneratorEqualsDemo.Person);
        }
 
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Equatable.SourceGenerator", "2.0.0+10ad4b045a688eb10980afcd11ddb8e64505eda6")]
        public static bool operator ==(global::GeneratorEqualsDemo.Person? left, global::GeneratorEqualsDemo.Person? right)
        {
            return global::System.Collections.Generic.EqualityComparer<global::GeneratorEqualsDemo.Person?>.Default.Equals(left, right);
        }
 
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Equatable.SourceGenerator", "2.0.0+10ad4b045a688eb10980afcd11ddb8e64505eda6")]
        public static bool operator !=(global::GeneratorEqualsDemo.Person? left, global::GeneratorEqualsDemo.Person? right)
        {
            return !(left == right);
        }
 
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Equatable.SourceGenerator", "2.0.0+10ad4b045a688eb10980afcd11ddb8e64505eda6")]
        public override int GetHashCode(){
            int hashCode = 1938039292;
            hashCode = (hashCode * -1521134295) + global::System.StringComparer.OrdinalIgnoreCase.GetHashCode(FirstName!);
            hashCode = (hashCode * -1521134295) + global::System.StringComparer.OrdinalIgnoreCase.GetHashCode(LastName!);
            return hashCode;
 
        }
 
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Equatable.Generator

[Interface2NullObject]Examples–part 3

Examples for rscg_Interface_to_null_object: Simplifying the Null Object Pattern

Now I can show some examples for rscg_Interface_to_null_object. This project aims to simplify the implementation of the Null Object Pattern in C# by automatically generating null object classes from interfaces.

I will start with those 2 interfaces:

1
2
3
4
5
6
7
8
using InterfaceToNullObject;
 
namespace IntegrationConsole;
[ToNullObject]
public interface IDepartment
{
    public string Name { get; set; }
}

and

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
using InterfaceToNullObject;
 
namespace IntegrationConsole;
[ToNullObject]
public interface IEmployee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public IDepartment Department { get; set; }
    public string GetFullName();
 
    public string GetFullNameAndDepartment(string separator);
    public bool MoveEmployeeToDepartment(IDepartment department);
 
}

The generated code is the following

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// <auto-generated>
    //     This code was generated by a tool :rscg_Interface_to_null_object
    //     Runtime Version: José Saramago is feeling diplomatic in Bissau
    //     DateOfTool : 2025-01-20 16:28:25
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
//------------------------------------------------------------------------------
/// <summary>
    /// This static partial class contains extension methods for sorting collections of IDepartment objects.
    /// </summary>
 
 #nullable enable
 #pragma warning disable CS8603
 #pragma warning disable CS8625
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCode("GeneratorName","2025.10120.11628.125")]
public partial class Department_null : global::IntegrationConsole.IDepartment
{
 
        public virtual string Name { get; set; } = default(string);
     
}
 
#nullable restore
#pragma warning restore CS8603
#pragma warning restore CS8625

And the employee

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// <auto-generated>
    //     This code was generated by a tool :rscg_Interface_to_null_object
    //     Runtime Version: José Saramago is feeling diplomatic in Bissau
    //     DateOfTool : 2025-01-20 16:28:25
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
//------------------------------------------------------------------------------
/// <summary>
    /// This static partial class contains extension methods for sorting collections of IEmployee objects.
    /// </summary>
 
 #nullable enable
 #pragma warning disable CS8603
 #pragma warning disable CS8625
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCode("GeneratorName","2025.10120.11628.125")]
public partial class Employee_null : global::IntegrationConsole.IEmployee
{
 
        public virtual string FirstName { get; set; } = default(string);
     
        public virtual string LastName { get; set; } = default(string);
     
        public virtual IntegrationConsole.IDepartment Department { get; set; } = default(IntegrationConsole.IDepartment);
     
        public virtual string GetFullName() { return default(string); }
     
        public virtual string GetFullNameAndDepartment(string separator) { return default(string); }
     
        public virtual bool MoveEmployeeToDepartment(global::IntegrationConsole.IDepartment department) { return default(bool); }
     
}
 
#nullable restore
#pragma warning restore CS8603
#pragma warning restore CS8625

So please checkout rscg_Interface_to_null_object.

[Interface2NullObject]Implementation–part2

Introducing rscg_Interface_to_null_object: Simplifying the Null Object Pattern

I’m excited to announce the release of my new project, rscg_Interface_to_null_object. This project aims to simplify the implementation of the Null Object Pattern in C# by automatically generating null object classes from interfaces.

Architecture Overview

The project is composed of two main components:

  1. Attribute Project: This project contains the attribute that you can apply to interfaces for which you want to generate null object classes.
  2. Generator Project: This project contains the logic for intercepting the interfaces with the attribute and generating the corresponding null object classes.

How It Works

Intercepting the Attribute

The generator project first intercepts the attribute applied to the interfaces. This allows it to identify which interfaces need null object classes.

1
2
3
4
5
6
7
8
        var classesToApplySortable = context.SyntaxProvider.ForAttributeWithMetadataName(
"InterfaceToNullObject.ToNullObjectAttribute",
IsAppliedOnInterface,
FindAttributeDataExpose
)
.Collect()
.SelectMany((data, _) => data.Distinct())
.Collect();

Generating Classes

Once the interfaces are identified, the generator uses a RazorBlade template to create the null object classes. This ensures that the generated classes are consistent and follow best practices.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@inherits RazorBlade.PlainTextTemplate<rscg_Interface_to_null_object.DataFromExposeInterface>
@{
    string nameClass = Model.Name.StartsWith("I")?Model.Name.Substring(1):Model.Name;
    nameClass += "_null";
}
// <auto-generated>
    //     This code was generated by a tool :@Generated.rscg_Interface_to_null_object.TheAssemblyInfo.AssemblyName
    //     Runtime Version: @Generated.rscg_Interface_to_null_object.TheAssemblyInfo.GeneratedNameNice
    //     DateOfTool : @Generated.rscg_Interface_to_null_object.TheAssemblyInfo.DateGeneratedUTC.ToString("yyyy-MM-dd HH:mm:ss")
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
//------------------------------------------------------------------------------
/// <summary>
    /// This static partial class contains extension methods for sorting collections of @Model.Name objects.
    /// </summary>
 
 #nullable enable
 #pragma warning disable CS8603
 #pragma warning disable CS8625
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCode("GeneratorName","@Generated.rscg_Interface_to_null_object.TheAssemblyInfo.DateGeneratedUTC.ToString("yyyy.1MMdd.1HHmm.1ss")")]
public partial class @(nameClass) : @Model.FullName
{
@foreach(var prop in Model.props){
    <text>
        public virtual @prop.Type @prop.Name { get; set; } = default(@prop.Type);
    </text>
}
@foreach (var func in Model.functions)
{
    <text>
        public virtual @func.ReturnType @Model.DisplayFunc(func) { return default(@func.ReturnType); }
    </text>
}
 
}
 
#nullable restore
#pragma warning restore CS8603
#pragma warning restore CS8625

Getting Started

To get started with rscg_Interface_to_null_object, you can add the NuGet packages to your project and apply the attribute to your interfaces. The generator will take care of the rest, creating the necessary null object classes for you.

For more details and examples, check out the GitHub repository.

Happy coding!

[Interface2NullObject] Idea- part 1

Every time I kick off a new project, I dive straight into classes/methods that do stuff – because who doesn’t love instant gratification? But now, I’m turning over a new leaf. From now on, I’m starting with interfaces and then gradually building out the classes that make the magic happen.

But here’s the catch – for every interface, I need a class with the same properties and methods, even if it just sits there doing nothing. Think of it like the https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.abstractions.nulllogger?view=net-9.0-pp or the Null Object Pattern.

So, how do I automate this? Enter Roslyn Source Code Generators! Roslyn will hand me the interface, methods, and properties on a silver platter, and I’ll have the class in no time!

RSCG – Darp.BinaryObjects

RSCG – Darp.BinaryObjects
 
 

name Darp.BinaryObjects
nuget https://www.nuget.org/packages/Darp.BinaryObjects/
link https://github.com/rosslight/Darp.BinaryObjects
author Ross Light GmbH

Serialize bits of data

 

This is how you can use Darp.BinaryObjects .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
   
    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
 
   
    <ItemGroup>
      <PackageReference Include="Darp.BinaryObjects" Version="0.4.0" />
    </ItemGroup>
 
</Project>

The code that you will use is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
using BitsDemo;
using Darp.BinaryObjects;
 
var z = new zlib_header(0x78, 0x9C);
 
var size = z.GetByteCount();
 
// Write the values back to a buffer
var writeBuffer = new byte[size];
if(z.TryWriteLittleEndian(writeBuffer))
{
    Console.WriteLine("writing to buffer" );
    foreach (var item in writeBuffer)
    {
        Console.Write(item+" ");
    }
}
01
02
03
04
05
06
07
08
09
10
using Darp.BinaryObjects;
using System.IO.Compression;
 
namespace BitsDemo;
 
[BinaryObject]
partial record zlib_header(byte cmf, byte flg)
{
     
}

 

The code that is generated is

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// <auto-generated/>
#nullable enable
 
namespace BitsDemo
{
    /// <remarks> <list type="table">
    /// <item> <term><b>Field</b></term> <description><b>Byte Length</b></description> </item>
    /// <item> <term><see cref="cmf"/></term> <description>1</description> </item>
    /// <item> <term><see cref="flg"/></term> <description>1</description> </item>
    /// <item> <term> --- </term> <description>2</description> </item>
    /// </list> </remarks>
    partial record zlib_header : global::Darp.BinaryObjects.IWritable, global::Darp.BinaryObjects.ISpanReadable<zlib_header>
    {
        /// <inheritdoc />
        [global::System.Diagnostics.Contracts.Pure]
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public int GetByteCount() => 2;
 
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public bool TryWriteLittleEndian(global::System.Span<byte> destination) => TryWriteLittleEndian(destination, out _);
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public bool TryWriteLittleEndian(global::System.Span<byte> destination, out int bytesWritten)
        {
            bytesWritten = 0;
 
            if (destination.Length < 2)
                return false;
            global::Darp.BinaryObjects.Generated.Utilities.WriteUInt8(destination[0..], this.cmf);
            global::Darp.BinaryObjects.Generated.Utilities.WriteUInt8(destination[1..], this.flg);
            bytesWritten += 2;
 
            return true;
        }
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public bool TryWriteBigEndian(global::System.Span<byte> destination) => TryWriteBigEndian(destination, out _);
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public bool TryWriteBigEndian(global::System.Span<byte> destination, out int bytesWritten)
        {
            bytesWritten = 0;
 
            if (destination.Length < 2)
                return false;
            global::Darp.BinaryObjects.Generated.Utilities.WriteUInt8(destination[0..], this.cmf);
            global::Darp.BinaryObjects.Generated.Utilities.WriteUInt8(destination[1..], this.flg);
            bytesWritten += 2;
 
            return true;
        }
 
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public static bool TryReadLittleEndian(global::System.ReadOnlySpan<byte> source, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out zlib_header? value) => TryReadLittleEndian(source, out value, out _);
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public static bool TryReadLittleEndian(global::System.ReadOnlySpan<byte> source, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out zlib_header? value, out int bytesRead)
        {
            bytesRead = 0;
            value = default;
 
            if (source.Length < 2)
                return false;
            var ___readcmf = global::Darp.BinaryObjects.Generated.Utilities.ReadUInt8(source[0..1]);
            var ___readflg = global::Darp.BinaryObjects.Generated.Utilities.ReadUInt8(source[1..2]);
            bytesRead += 2;
 
            value = new zlib_header(___readcmf, ___readflg);
            return true;
        }
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public static bool TryReadBigEndian(global::System.ReadOnlySpan<byte> source, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out zlib_header? value) => TryReadBigEndian(source, out value, out _);
        /// <inheritdoc />
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
        public static bool TryReadBigEndian(global::System.ReadOnlySpan<byte> source, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out zlib_header? value, out int bytesRead)
        {
            bytesRead = 0;
            value = default;
 
            if (source.Length < 2)
                return false;
            var ___readcmf = global::Darp.BinaryObjects.Generated.Utilities.ReadUInt8(source[0..1]);
            var ___readflg = global::Darp.BinaryObjects.Generated.Utilities.ReadUInt8(source[1..2]);
            bytesRead += 2;
 
            value = new zlib_header(___readcmf, ___readflg);
            return true;
        }
    }
}
 
namespace Darp.BinaryObjects.Generated
{
    using Darp.BinaryObjects;
    using System;
    using System.Buffers.Binary;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
 
    /// <summary>Helper methods used by generated BinaryObjects.</summary>
    [GeneratedCodeAttribute("Darp.BinaryObjects.Generator", "0.4.0.0")]
    file static class Utilities
    {
        /// <summary> Writes a <c>byte</c> to the destination </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void WriteUInt8(Span<byte> destination, byte value)
        {
            destination[0] = value;
        }
        /// <summary> Reads a <c>byte</c> from the given source </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static byte ReadUInt8(ReadOnlySpan<byte> source)
        {
            return source[0];
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Darp.BinaryObjects

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.