Category: .NET

NetPackageAnalyzer–part 12-CyclomaticComplexity

The .NET Tool , https://www.nuget.org/packages/netpackageanalyzerconsole , can now analyze a solution and see the cyclomatic complexity.

Cyclomatic Complexity for assembly, class, method

The cyclomatic complexity of a section of code is the number of linearly independent paths through the code. It is a quantitative measure of the number of linearly independent paths through a program’s source code.

The program is showing the cyclomatic complexity of the assembly, class, and method. You should start with the method – it is the easy to analyze .

diagram

Also , you can see on which methods you should focus to refactor – the ones with the highest cyclomatic complexity.

diagram

https://learn.microsoft.com/en-us/visualstudio/code-quality/code-metrics-cyclomatic-complexity?view=vs-2022

Install from https://nuget.org/packages/netpackageanalyzerconsole

RSCG – Sera.Union

RSCG – Sera.Union
 
 

name Sera.Union
nuget https://www.nuget.org/packages/Sera.Union/
link https://github.com/sera-net/Sera.Union
author Sera

Generate tagged union

 

This is how you can use Sera.Union .

The code that you start with is


<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="Sera.Union" Version="0.7.0" />
	</ItemGroup>

</Project>


The code that you will use is


using UnionTypesDemo;

Console.WriteLine("Save or not");
var data = SaveToDatabase.Save(0);
Console.WriteLine(data.IsNotFound);
data = SaveToDatabase.Save(1);
if(data.IsOk)
{
    Console.WriteLine(data.Tag);
    Console.WriteLine(data.Ok);
}


 

The code that is generated is

// <auto-generated/>

#nullable enable

using Sera.TaggedUnion;

namespace UnionTypesDemo {

public partial struct ResultSave
    : global::Sera.TaggedUnion.ITaggedUnion
    , global::System.IEquatable<ResultSave>
    , global::System.IComparable<ResultSave>
#if NET7_0_OR_GREATER
    , global::System.Numerics.IEqualityOperators<ResultSave, ResultSave, bool>
    , global::System.Numerics.IComparisonOperators<ResultSave, ResultSave, bool>
#endif
{
    private __impl_ _impl;
    private ResultSave(__impl_ _impl) { this._impl = _impl; }

    public readonly Tags Tag
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag;
    }

    public enum Tags : byte
    {
        Ok = 1,
        NotFound = 2,
    }

    [global::System.Runtime.CompilerServices.CompilerGenerated]
    private struct __impl_
    {
        public __unmanaged_ _unmanaged_;
        public readonly Tags _tag;

        [global::System.Runtime.CompilerServices.CompilerGenerated]
        [global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Explicit)]
        internal struct __unmanaged_
        {
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public int _0;
        }

        public __impl_(Tags _tag)
        {
            global::System.Runtime.CompilerServices.Unsafe.SkipInit(out this._unmanaged_);
            this._tag = _tag;
        }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static ResultSave MakeOk(int value)
    {
        var _impl = new __impl_(Tags.Ok);
        _impl._unmanaged_._0 = value;
        return new ResultSave(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static ResultSave MakeNotFound()
    {
        var _impl = new __impl_(Tags.NotFound);
        return new ResultSave(_impl);
    }

    public readonly bool IsOk
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.Ok;
    }
    public readonly bool IsNotFound
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.NotFound;
    }

    public int Ok
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        readonly get => !this.IsOk ? default! : this._impl._unmanaged_._0!;
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        set { if (this.IsOk) { this._impl._unmanaged_._0 = value; } }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly bool Equals(ResultSave other) => this.Tag != other.Tag ? false : this.Tag switch
    {
        Tags.Ok => global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(this.Ok, other.Ok),
        _ => true,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override int GetHashCode() => this.Tag switch
    {
        Tags.Ok => global::System.HashCode.Combine(this.Tag, this.Ok),
        _ => global::System.HashCode.Combine(this.Tag),
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override bool Equals(object? obj) => obj is ResultSave other && Equals(other);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator ==(ResultSave left, ResultSave right) => Equals(left, right);
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator !=(ResultSave left, ResultSave right) => !Equals(left, right);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly int CompareTo(ResultSave other) => this.Tag != other.Tag ? global::System.Collections.Generic.Comparer<Tags>.Default.Compare(this.Tag, other.Tag) : this.Tag switch
    {
        Tags.Ok => global::System.Collections.Generic.Comparer<int>.Default.Compare(this.Ok, other.Ok),
        _ => 0,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <(ResultSave left, ResultSave right) => left.CompareTo(right) < 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >(ResultSave left, ResultSave right) => left.CompareTo(right) > 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <=(ResultSave left, ResultSave right) => left.CompareTo(right) <= 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >=(ResultSave left, ResultSave right) => left.CompareTo(right) >= 0;

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override string ToString() => this.Tag switch
    {
        Tags.Ok => $"{nameof(ResultSave)}.{nameof(Tags.Ok)} {{ {this.Ok} }}",
        Tags.NotFound => $"{nameof(ResultSave)}.{nameof(Tags.NotFound)}",
        _ => nameof(ResultSave),
    };
}

} // namespace UnionTypesDemo

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Sera.Union

RSCG – RSCG_NameGenerator

RSCG – RSCG_NameGenerator
 
 

name RSCG_NameGenerator
nuget https://www.nuget.org/packages/RSCG_NameGenerator/
link https://github.com/ignatandrei/NameGenerator/
author Andrei Ignat

Generating unique names for assemblies

 

This is how you can use RSCG_NameGenerator .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
	
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="RSCG_NameGenerator" Version="2024.26.8.2002" >
			<OutputItemType>Analyzer</OutputItemType>
			<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
		</PackageReference>
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using Generated.TestNameGenerator;
//by just putting here
//you will not deploy the dll when you deploy the project
//name are generated in the code source
Console.WriteLine($"Name:{TheAssemblyInfo.GeneratedName}");
Console.WriteLine($"Nice:{TheAssemblyInfo.GeneratedNameNice}");
Console.WriteLine($"Small:{TheAssemblyInfo.GeneratedNameSmall}");
//if you want to generate a new name every time you run the app
//put in the csproj
//<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
//but the dll will be deployed with the app
//Console.WriteLine(NameGenerator.NameGeneratorData.Generate().UniqueNameLong);

 

The code that is generated is


                // <auto-generated/>
                namespace Generated.TestNameGenerator
                {
                    public static class TheAssemblyInfo
                    {
                        public const string AssemblyName = "TestNameGenerator";
                        public const string GeneratedNameNice = "Sir Winston Churchill is feeling private in Naypyidaw";
                        public const string GeneratedNameSmall = "private-Sir Winston Churchill";
                        public const string GeneratedName = "private-Sir Winston Churchill-Naypyidaw";
                        
                    }
                }

Code and pdf at

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

RSCG – Fluentify

RSCG – Fluentify
 
 

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

Generate fluent builder

 

This is how you can use Fluentify .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

	  <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>

	  <ItemGroup>
	    <PackageReference Include="Fluentify" 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


using Builder;

var pOld = new Person();
pOld= pOld.WithFirstName("Andrei").WithLastName("Ignat").WithMiddleName("G");

System.Console.WriteLine(pOld.FullName());



namespace Builder;
[Fluentify.Fluentify]
public partial class Person
{
    public string FirstName { get; init; }
    public string? MiddleName { get; init; }
    public string LastName { get; init; }

    public string FullName()
    {
        return FirstName + " " + MiddleName + " "+LastName;
    }
    
}


 

The code that is generated is

#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable enable
#endif

#pragma warning disable CS8625

namespace Builder
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Fluentify.Internal;

    public static partial class PersonExtensions
    {
        public static global::Builder.Person WithFirstName(
            this global::Builder.Person subject,
            string value)
        {
            subject.ThrowIfNull("subject");

            return new global::Builder.Person
            {
                FirstName = value,
                MiddleName = subject.MiddleName,
                LastName = subject.LastName,
            };
        }
    }
}

#pragma warning restore CS8625

#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable enable
#endif

#pragma warning disable CS8625

namespace Builder
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Fluentify.Internal;

    public static partial class PersonExtensions
    {
        public static global::Builder.Person WithLastName(
            this global::Builder.Person subject,
            string value)
        {
            subject.ThrowIfNull("subject");

            return new global::Builder.Person
            {
                FirstName = subject.FirstName,
                MiddleName = subject.MiddleName,
                LastName = value,
            };
        }
    }
}

#pragma warning restore CS8625

#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable enable
#endif

#pragma warning disable CS8625

namespace Builder
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Fluentify.Internal;

    public static partial class PersonExtensions
    {
        public static global::Builder.Person WithMiddleName(
            this global::Builder.Person subject,
            string? value)
        {
            subject.ThrowIfNull("subject");

            return new global::Builder.Person
            {
                FirstName = subject.FirstName,
                MiddleName = value,
                LastName = subject.LastName,
            };
        }
    }
}

#pragma warning restore CS8625

#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
namespace Fluentify
{
    using System;
    using System.Diagnostics.CodeAnalysis;

    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
    internal sealed class DescriptorAttribute
        : Attribute
    {
        public DescriptorAttribute(string value)
        {
            Value = value;
        }

        public string Value { get; }
    }
}
namespace Fluentify
{
    using System;

    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    internal sealed class FluentifyAttribute
        : Attribute
    {
    }
}
namespace Fluentify
{
    using System;

    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
    internal sealed class IgnoreAttribute
        : Attribute
    {
    }
}
namespace Fluentify.Internal
{
    using System;

    internal static class Extensions
    {
        public static void ThrowIfNull(this object subject, string paramName)
        {
            if (subject == null)
            {
                throw new ArgumentNullException(paramName);
            }
        }
    }
}

Code and pdf at

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

RSCG – RSCG_ExportDiagram

RSCG – RSCG_ExportDiagram
 
 

name RSCG_ExportDiagram
nuget https://github.com/ignatandrei/RSCG_ExportDiagram
link RSCG_ExportDiagram
author AndreiIgnat

Generating diagram for relation classes within referenced project

 

This is how you can use RSCG_ExportDiagram .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<ItemGroup>
		<PackageReference Include="RSCG_ExportDiagram" Version="2024.810.832" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
	</ItemGroup>
	<ItemGroup>
		<CompilerVisibleProperty Include="RSCG_ExportDiagram_OutputFolder" />
		<CompilerVisibleProperty Include="RSCG_ExportDiagram_Exclude" />
	</ItemGroup>
	<ItemGroup>
	  <ProjectReference Include="..\Person\Person.csproj" />
	</ItemGroup>
	<PropertyGroup>
		<RSCG_ExportDiagram_OutputFolder>obj/GX/</RSCG_ExportDiagram_OutputFolder>
		<RSCG_ExportDiagram_Exclude></RSCG_ExportDiagram_Exclude>
	</PropertyGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using Person;

internal class Program
{
    private static void Main(string[] args)
    {
        PersonData person = new ();
        person.Name = "Andrei Ignat";
        Console.WriteLine(person.Name);
    }
}


namespace Person;

public class PersonData
{
    public string Name { get; set; }
    public int Age { get; set; }
}




 

The code that is generated is


//JSONFolder=obj/GX/
//projectDir=D:\gth\RSCG_Examples\v2\rscg_examples\RSCG_ExportDiagram\src\DiagramDemo\DiagramDemoConsole\
//projectName=DiagramDemoConsole
//excludeData=
file class Program_References_1
{
    public Program_References_1()
{
     

// Method Main has following external references
// Person.PersonData..ctor
//Person.PersonData.Name

}
}

Code and pdf at

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

RSCG – ThisAssembly.Strings

RSCG – ThisAssembly.Strings
 
 

name ThisAssembly.Strings
nuget https://www.nuget.org/packages/ThisAssembly.Strings/
link https://github.com/devlooped/ThisAssembly
author Daniel Cazzulino

generating code from resx files

 

This is how you can use ThisAssembly.Strings .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="ThisAssembly.Strings" Version="1.4.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

  <ItemGroup>
    <Compile Update="Demo.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Demo.resx</DependentUpon>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Update="Demo.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Demo.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


Console.WriteLine(ThisAssembly.Strings.PersonName("Andrei Ignat"));



<?xml version="1.0" encoding="utf-8"?>
<root>
  <!-- 
    Microsoft ResX Schema 
    
    Version 2.0
    
    The primary goals of this format is to allow a simple XML format 
    that is mostly human readable. The generation and parsing of the 
    various data types are done through the TypeConverter classes 
    associated with the data types.
    
    Example:
    
    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>
                
    There are any number of "resheader" rows that contain simple 
    name/value pairs.
    
    Each data row contains a name, and value. The row also contains a 
    type or mimetype. Type corresponds to a .NET class that support 
    text/value conversion through the TypeConverter architecture. 
    Classes that don't support this are serialized and stored with the 
    mimetype set.
    
    The mimetype is used for serialized objects, and tells the 
    ResXResourceReader how to depersist the object. This is currently not 
    extensible. For a given mimetype the value must be set accordingly:
    
    Note - application/x-microsoft.net.object.binary.base64 is the format 
    that the ResXResourceWriter will generate, however the reader can 
    read any of the formats listed below.
    
    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with 
            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.
    
    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with 
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.

    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array 
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="PersonName" xml:space="preserve">
    <value>The person name is {0}</value>
    <comment>the person name</comment>
  </data>
</root>

 

The code that is generated is

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Strings: 1.4.3
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Globalization;

partial class ThisAssembly
{
    public static partial class Strings
    {
        /// <summary>
        /// the person name
        /// </summary>
        public static string PersonName(object arg0) => string.Format(CultureInfo.CurrentCulture, Strings.GetResourceManager("StringsDemo.Demo").GetString("PersonName"), arg0);
    }
}
using System.Collections.Concurrent;
using System.Resources;
using System.Runtime.CompilerServices;

/// <summary>
/// Provides access to the current assembly information as pure constants, 
///  without requiring reflection.
/// </summary>
partial class ThisAssembly
{
    /// <summary>
    /// Access the strings provided by resource files in the project.
    /// </summary>
    [CompilerGenerated]
    public static partial class Strings
    {
        static ConcurrentDictionary<string, ResourceManager> resourceManagers = new ConcurrentDictionary<string, ResourceManager>();

        static ResourceManager GetResourceManager(string resourceName)
            => resourceManagers.GetOrAdd(resourceName, name => new ResourceManager(name, typeof(Strings).Assembly));
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/ThisAssembly.Strings

RSCG – ThisAssembly.Metadata

RSCG – ThisAssembly.Metadata    

name ThisAssembly.Metadata
nuget https://www.nuget.org/packages/ThisAssembly.Metadata/
link https://github.com/devlooped/ThisAssembly
author Daniel Cazzulino

Generating code from assembly metadata

 

This is how you can use ThisAssembly.Metadata .

The code that you start with is

  <Project Sdk="Microsoft.NET.Sdk">    <PropertyGroup>     <OutputType>Exe</OutputType>     <TargetFramework>net8.0</TargetFramework>     <ImplicitUsings>enable</ImplicitUsings>     <Nullable>enable</Nullable>   </PropertyGroup> 	<ItemGroup> 		<AssemblyMetadata Include="MyName" Value="Andrei" /> 	</ItemGroup> 	<ItemGroup> 	  <PackageReference Include="ThisAssembly.Metadata" Version="1.4.3"> 	    <PrivateAssets>all</PrivateAssets> 	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> 	  </PackageReference> 	</ItemGroup> 	<PropertyGroup> 		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> 		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> 	</PropertyGroup> </Project>   

The code that you will use is

  [assembly: System.Reflection.AssemblyMetadataAttribute("Name", "Test")]  Console.WriteLine(ThisAssembly.Metadata.Name); Console.WriteLine(ThisAssembly.Metadata.MyName);   

  The code that is generated is

 //------------------------------------------------------------------------------ // <auto-generated> //     This code was generated by a tool. // //     Changes to this file may cause incorrect behavior and will be lost if //     the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------  using System.CodeDom.Compiler; using System.Runtime.CompilerServices;  /// <summary> /// Provides access to the current assembly information as pure constants,  ///  without requiring reflection. /// </summary> partial class ThisAssembly {     /// <summary>     /// Gets the assembly metadata.     /// </summary>     [GeneratedCode("ThisAssembly.Metadata", "1.4.3")]     [CompilerGenerated]     public static partial class Metadata     {         /// <summary>Name = Test</summary>         public const string Name =  """ Test """;          /// <summary>MyName = Andrei</summary>         public const string MyName =  """ Andrei """;      } } 

Code and pdf at https://ignatandrei.github.io/RSCG_Examples/v2/docs/ThisAssembly.Metadata

RSCG – Pekspro.BuildInformationGenerator

RSCG – Pekspro.BuildInformationGenerator    

name Pekspro.BuildInformationGenerator
nuget https://www.nuget.org/packages/Pekspro.BuildInformationGenerator/
link https://github.com/pekspro/BuildInformationGenerator
author pekspro

adding git build information

  

This is how you can use Pekspro.BuildInformationGenerator .

The code that you start with is


<project sdk="Microsoft.NET.Sdk">

  <propertygroup>
    <outputtype>Exe</outputtype>
    <targetframework>net8.0</targetframework>
    <implicitusings>enable</implicitusings>
    <nullable>enable</nullable>
  </propertygroup>

  <itemgroup>
    <packagereference version="0.2.0" include="Pekspro.BuildInformationGenerator">
  </packagereference>
	<propertygroup>
		<emitcompilergeneratedfiles>true</emitcompilergeneratedfiles>
		<compilergeneratedfilesoutputpath>$(BaseIntermediateOutputPath)\GX</compilergeneratedfilesoutputpath>
	</propertygroup>
</itemgroup>


The code that you will use is


using BuildInfo;

Console.WriteLine(MyBuildInfo.Git.CommitId);
Console.WriteLine(MyBuildInfo.Git.Branch);
Console.WriteLine(MyBuildInfo.AssemblyVersionString);




using Pekspro.BuildInformationGenerator;

namespace BuildInfo;
[BuildInformation(AddBuildTime = true, 
    AddGitCommitId = true,
    AddAssemblyVersion = true,
    AddDotNetSdkVersion = true,
    AddGitBranch = true,
    AddLocalBuildTime= true,
    AddOSVersion = true,    
    FakeIfDebug =false,
    FakeIfRelease =false)]
partial class MyBuildInfo
{
}


   The code that is generated is

//---------------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the Pekspro.BuildInformationGenerator source generator.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//---------------------------------------------------------------------------------------

namespace BuildInfo
{
    /// <summary>
    /// Build information.
    /// </summary>
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Pekspro.BuildInformationGenerator", "0.2.0")]
    static partial class MyBuildInfo
    {

        /// <summary>
        /// Build time: 2024-07-18 19:57:53
        /// Value was taken from the system clock.
        /// </summary>
        public static readonly global::System.DateTime BuildTime = new global::System.DateTime(638569294731432248L, global::System.DateTimeKind.Utc);

        /// <summary>
        /// Local build time: 2024-07-18 22:57:53 (+03:00)
        /// Value was taken from the system clock.
        /// </summary>
        public static readonly global::System.DateTimeOffset LocalBuildTime = new global::System.DateTimeOffset(638569402731432248L, new global::System.TimeSpan(108000000000));

        /// <summary>
        /// Build information related to git.
        /// </summary>
        static public partial class Git
        {

            /// <summary>
            /// The commit id in git at the time of build.
            /// Value was taken from the AssemblyInformationalVersion attribute.
            /// </summary>
            public const string CommitId = "51a6dd67bbe091af607870fd80a52ea54d249e47";

            /// <summary>
            /// The short commit id in git at the time of build.
            /// Value was taken from the AssemblyInformationalVersion attribute.
            /// </summary>
            public const string ShortCommitId = "51a6dd67";

            /// <summary>
            /// The git branch used at build time.
            /// Value was taken from the git branch command.
            /// </summary>
            public const string Branch = "278-httpsgithubcompeksprobuildinformationgenerator";

        }

        /// <summary>
        /// Version of the assembly.
        /// Value was taken from assembly version attribute.
        /// </summary>
        public const string AssemblyVersionString = "1.0.0.0";

        /// <summary>
        /// OS version of the building machine.
        /// Value was taken from Environment.OSVersion.
        /// </summary>
        public const string OSVersion = "Microsoft Windows NT 6.2.9200.0";

        /// <summary>
        /// .NET SDK version used at build time.
        /// Value was taken from the dotnet --version command.
        /// </summary>
        public const string DotNetSdkVersion = "8.0.303";

    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Pekspro.BuildInformationGenerator

RSCG – ThisAssembly.Constants

RSCG – ThisAssembly.Constants    

name ThisAssembly.Constants
nuget https://www.nuget.org/packages/ThisAssembly.Constants/
link https://github.com/devlooped/ThisAssembly
author Daniel Cazzulino

Generating Constants from csproj

 

This is how you can use ThisAssembly.Constants .

The code that you start with is

  <Project Sdk="Microsoft.NET.Sdk">    <PropertyGroup>     <OutputType>Exe</OutputType>     <TargetFramework>net8.0</TargetFramework>     <ImplicitUsings>enable</ImplicitUsings>     <Nullable>enable</Nullable>   </PropertyGroup>    <ItemGroup> 	  <Constant Include="TimeOut" Value="100" Comment="Test" />     <PackageReference Include="ThisAssembly.Constants" Version="1.4.3">       <PrivateAssets>all</PrivateAssets>       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>     </PackageReference>   </ItemGroup> 	<PropertyGroup> 		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> 		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> 	</PropertyGroup> </Project>   

The code that you will use is

  Console.WriteLine(ThisAssembly.Constants.TimeOut);  

  The code that is generated is

 //------------------------------------------------------------------------------ // <auto-generated> //     This code was generated by a tool. // //     ThisAssembly.Constants: 1.4.3 // //     Changes to this file may cause incorrect behavior and will be lost if //     the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ using System; using System.Globalization;  partial class ThisAssembly {     public static partial class Constants     {         /// <summary>         /// Test         /// </summary>         public const string TimeOut = """ 100 """;     } } 

Code and pdf at https://ignatandrei.github.io/RSCG_Examples/v2/docs/ThisAssembly.Constants

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.