RSCG – polytype

RSCG – polytype
 
 

name polytype
nuget https://www.nuget.org/packages/polytype/
link https://github.com/eiriktsarpalis/PolyType
author Eirik Tsarpalis

Generating shape like reflection from classes. See PolyType.Examples for more details

 

This is how you can use polytype .

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="PolyType" Version="0.16.1" />
    <PackageReference Include="PolyType.Examples" Version="0.16.1" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using PolyType.Examples.JsonSerializer;
using PolyType.Examples.CborSerializer;
using PolyType.Examples.XmlSerializer;
using ConsoleApp1;
using PolyType.Examples.Cloner;

Person person = new("Pete", 70);
Console.WriteLine(JsonSerializerTS.Serialize(person)); // {"Name":"Pete","Age":70}
Console.WriteLine(XmlSerializer.Serialize(person));    // <value><Name>Pete</Name><Age>70</Age></value>
Console.WriteLine(CborSerializer.EncodeToHex(person)); // A2644E616D656450657465634167651846
person.Childs = [new Person("Andrei", 55)];

person.Childs[0].ID = 1;
var q = Cloner.Clone(person);
person.Childs[0].ID = 10;
Console.WriteLine(q);
Console.WriteLine(person);
Console.WriteLine(q.Childs[0]);
Console.WriteLine(person.Childs[0]);



using PolyType;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1;
[GenerateShape]
public partial record Person(string name, int age)
{
    public Person[] Childs { get; set; } = [];

    public int ID;
}

 

The code that is generated is

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace ConsoleApp1
{
    public partial record Person : global::PolyType.IShapeable<global::ConsoleApp1.Person>
    {
        static global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person> global::PolyType.IShapeable<global::ConsoleApp1.Person>.GetShape() 
            => global::PolyType.SourceGenerator.GenerateShapeProvider.Default.Person;
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace PolyType.SourceGenerator
{
    internal partial class GenerateShapeProvider
    {
        private const global::System.Reflection.BindingFlags InstanceBindingFlags = 
            global::System.Reflection.BindingFlags.Public | 
            global::System.Reflection.BindingFlags.NonPublic | 
            global::System.Reflection.BindingFlags.Instance;
        
        /// <summary>Gets the default instance of the <see cref="GenerateShapeProvider"/> class.</summary>
        public static GenerateShapeProvider Default { get; } = new();
        
        /// <summary>Initializes a new instance of the <see cref="GenerateShapeProvider"/> class.</summary>
        public GenerateShapeProvider() { }
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace PolyType.SourceGenerator
{
    internal partial class GenerateShapeProvider
    {
        /// <summary>Gets the generated shape for specified type.</summary>
#nullable disable annotations // Use nullable-oblivious property type
        public global::PolyType.Abstractions.ITypeShape<int> Int32 => _Int32 ??= Create_Int32();
#nullable enable annotations // Use nullable-oblivious property type
        private global::PolyType.Abstractions.ITypeShape<int>? _Int32;

        private global::PolyType.Abstractions.ITypeShape<int> Create_Int32()
        {
            return new global::PolyType.SourceGenModel.SourceGenObjectTypeShape<int>
            {
                Provider = this,
                IsRecordType = false,
                IsTupleType = false,
                CreatePropertiesFunc = null,
                CreateConstructorFunc = null,
            };
        }
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace PolyType.SourceGenerator
{
    internal partial class GenerateShapeProvider : global::PolyType.ITypeShapeProvider
    {
        /// <summary>
        /// Gets the generated <see cref="global::PolyType.Abstractions.ITypeShape{T}" /> for the specified type.
        /// </summary>
        /// <typeparam name="T">The type for which a shape is requested.</typeparam>
        /// <returns>
        /// The generated <see cref="global::PolyType.Abstractions.ITypeShape{T}" /> for the specified type.
        /// </returns>
        public global::PolyType.Abstractions.ITypeShape<T>? GetShape<T>()
            => (global::PolyType.Abstractions.ITypeShape<T>?)GetShape(typeof(T));
        
        /// <summary>
        /// Gets the generated <see cref="global::PolyType.Abstractions.ITypeShape" /> for the specified type.
        /// </summary>
        /// <param name="type">The type for which a shape is requested.</param>
        /// <returns>
        /// The generated <see cref="global::PolyType.Abstractions.ITypeShape" /> for the specified type.
        /// </returns>
        public global::PolyType.Abstractions.ITypeShape? GetShape(global::System.Type type)
        {
            if (type == typeof(global::ConsoleApp1.Person[]))
                return Person_Array;
            
            if (type == typeof(string))
                return String;
            
            if (type == typeof(global::ConsoleApp1.Person))
                return Person;
            
            if (type == typeof(int))
                return Int32;
            
            return null;
        }
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace PolyType.SourceGenerator
{
    internal partial class GenerateShapeProvider
    {
        /// <summary>Gets the generated shape for specified type.</summary>
#nullable disable annotations // Use nullable-oblivious property type
        public global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person> Person => _Person ??= Create_Person();
#nullable enable annotations // Use nullable-oblivious property type
        private global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person>? _Person;

        private global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person> Create_Person()
        {
            return new global::PolyType.SourceGenModel.SourceGenObjectTypeShape<global::ConsoleApp1.Person>
            {
                Provider = this,
                IsRecordType = true,
                IsTupleType = false,
                CreatePropertiesFunc = CreateProperties_Person,
                CreateConstructorFunc = CreateConstructor_Person,
            };
        }

        private global::PolyType.Abstractions.IPropertyShape[] CreateProperties_Person() => new global::PolyType.Abstractions.IPropertyShape[]
        {
            new global::PolyType.SourceGenModel.SourceGenPropertyShape<global::ConsoleApp1.Person, string>
            {
                Name = "name",
                DeclaringType = (global::PolyType.Abstractions.IObjectTypeShape<global::ConsoleApp1.Person>)Person,
                PropertyType = String,
                Getter = static (ref global::ConsoleApp1.Person obj) => obj.name,
                Setter = null,
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetProperty("name", InstanceBindingFlags, null, typeof(string), [], null),
                IsField = false,
                IsGetterPublic = true,
                IsSetterPublic = false,
                IsGetterNonNullable = true,
                IsSetterNonNullable = false,
            },

            new global::PolyType.SourceGenModel.SourceGenPropertyShape<global::ConsoleApp1.Person, int>
            {
                Name = "age",
                DeclaringType = (global::PolyType.Abstractions.IObjectTypeShape<global::ConsoleApp1.Person>)Person,
                PropertyType = Int32,
                Getter = static (ref global::ConsoleApp1.Person obj) => obj.age,
                Setter = null,
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetProperty("age", InstanceBindingFlags, null, typeof(int), [], null),
                IsField = false,
                IsGetterPublic = true,
                IsSetterPublic = false,
                IsGetterNonNullable = true,
                IsSetterNonNullable = false,
            },

            new global::PolyType.SourceGenModel.SourceGenPropertyShape<global::ConsoleApp1.Person, global::ConsoleApp1.Person[]>
            {
                Name = "Childs",
                DeclaringType = (global::PolyType.Abstractions.IObjectTypeShape<global::ConsoleApp1.Person>)Person,
                PropertyType = Person_Array,
                Getter = static (ref global::ConsoleApp1.Person obj) => obj.Childs,
                Setter = static (ref global::ConsoleApp1.Person obj, global::ConsoleApp1.Person[] value) => obj.Childs = value,
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetProperty("Childs", InstanceBindingFlags, null, typeof(global::ConsoleApp1.Person[]), [], null),
                IsField = false,
                IsGetterPublic = true,
                IsSetterPublic = true,
                IsGetterNonNullable = true,
                IsSetterNonNullable = true,
            },

            new global::PolyType.SourceGenModel.SourceGenPropertyShape<global::ConsoleApp1.Person, int>
            {
                Name = "ID",
                DeclaringType = (global::PolyType.Abstractions.IObjectTypeShape<global::ConsoleApp1.Person>)Person,
                PropertyType = Int32,
                Getter = static (ref global::ConsoleApp1.Person obj) => obj.ID,
                Setter = static (ref global::ConsoleApp1.Person obj, int value) => obj.ID = value,
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetField("ID", InstanceBindingFlags),
                IsField = true,
                IsGetterPublic = true,
                IsSetterPublic = true,
                IsGetterNonNullable = true,
                IsSetterNonNullable = true,
            },
        };

        private global::PolyType.Abstractions.IConstructorShape CreateConstructor_Person()
        {
            return new global::PolyType.SourceGenModel.SourceGenConstructorShape<global::ConsoleApp1.Person, (string, int, global::ConsoleApp1.Person[], int, byte Flags)>
            {
                DeclaringType = (global::PolyType.Abstractions.IObjectTypeShape<global::ConsoleApp1.Person>)Person,
                ParameterCount = 4,
                GetParametersFunc = CreateConstructorParameters_Person,
                DefaultConstructorFunc = null,
                ArgumentStateConstructorFunc = static () => default((string, int, global::ConsoleApp1.Person[], int, byte Flags)),
                ParameterizedConstructorFunc = static (ref (string, int, global::ConsoleApp1.Person[], int, byte Flags) state) => { var obj = new global::ConsoleApp1.Person(state.Item1, state.Item2);  if ((state.Flags & 1) != 0) obj.Childs = state.Item3; if ((state.Flags & 2) != 0) obj.ID = state.Item4; return obj; },
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetConstructor(InstanceBindingFlags, new[] { typeof(string), typeof(int) }),
                IsPublic = true,
            };
        }

        private global::PolyType.Abstractions.IConstructorParameterShape[] CreateConstructorParameters_Person() => new global::PolyType.Abstractions.IConstructorParameterShape[]
        {
            new global::PolyType.SourceGenModel.SourceGenConstructorParameterShape<(string, int, global::ConsoleApp1.Person[], int, byte Flags), string>
            {
                Position = 0,
                Name = "name",
                ParameterType = String,
                Kind = global::PolyType.Abstractions.ConstructorParameterKind.ConstructorParameter,
                IsRequired = true,
                IsNonNullable = true,
                IsPublic = true,
                HasDefaultValue = false,
                DefaultValue = default!,
                Setter = static (ref (string, int, global::ConsoleApp1.Person[], int, byte Flags) state, string value) => state.Item1 = value,
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetConstructor(InstanceBindingFlags, new[] { typeof(string), typeof(int) })?.GetParameters()[0],
            },

            new global::PolyType.SourceGenModel.SourceGenConstructorParameterShape<(string, int, global::ConsoleApp1.Person[], int, byte Flags), int>
            {
                Position = 1,
                Name = "age",
                ParameterType = Int32,
                Kind = global::PolyType.Abstractions.ConstructorParameterKind.ConstructorParameter,
                IsRequired = true,
                IsNonNullable = true,
                IsPublic = true,
                HasDefaultValue = false,
                DefaultValue = default,
                Setter = static (ref (string, int, global::ConsoleApp1.Person[], int, byte Flags) state, int value) => state.Item2 = value,
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetConstructor(InstanceBindingFlags, new[] { typeof(string), typeof(int) })?.GetParameters()[1],
            },

            new global::PolyType.SourceGenModel.SourceGenConstructorParameterShape<(string, int, global::ConsoleApp1.Person[], int, byte Flags), global::ConsoleApp1.Person[]>
            {
                Position = 2,
                Name = "Childs",
                ParameterType = Person_Array,
                Kind = global::PolyType.Abstractions.ConstructorParameterKind.PropertyInitializer,
                IsRequired = false,
                IsNonNullable = true,
                IsPublic = true,
                HasDefaultValue = false,
                DefaultValue = default!,
                Setter = static (ref (string, int, global::ConsoleApp1.Person[], int, byte Flags) state, global::ConsoleApp1.Person[] value) => { state.Item3 = value; state.Flags |= 1; },
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetProperty("Childs", InstanceBindingFlags, null, typeof(global::ConsoleApp1.Person[]), [], null),
            },

            new global::PolyType.SourceGenModel.SourceGenConstructorParameterShape<(string, int, global::ConsoleApp1.Person[], int, byte Flags), int>
            {
                Position = 3,
                Name = "ID",
                ParameterType = Int32,
                Kind = global::PolyType.Abstractions.ConstructorParameterKind.FieldInitializer,
                IsRequired = false,
                IsNonNullable = true,
                IsPublic = true,
                HasDefaultValue = false,
                DefaultValue = default,
                Setter = static (ref (string, int, global::ConsoleApp1.Person[], int, byte Flags) state, int value) => { state.Item4 = value; state.Flags |= 2; },
                AttributeProviderFunc = static () => typeof(global::ConsoleApp1.Person).GetField("ID", InstanceBindingFlags),
            },
        };

        [global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_name")]
        private static extern void Person_name_SetAccessor(global::ConsoleApp1.Person obj, string value);

        [global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_age")]
        private static extern void Person_age_SetAccessor(global::ConsoleApp1.Person obj, int value);

        [global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Field, Name = "ID")]
        private static extern ref int Person_ID_Accessor(global::ConsoleApp1.Person obj);
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace PolyType.SourceGenerator
{
    internal partial class GenerateShapeProvider
    {
        /// <summary>Gets the generated shape for specified type.</summary>
#nullable disable annotations // Use nullable-oblivious property type
        public global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person[]> Person_Array => _Person_Array ??= Create_Person_Array();
#nullable enable annotations // Use nullable-oblivious property type
        private global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person[]>? _Person_Array;

        private global::PolyType.Abstractions.ITypeShape<global::ConsoleApp1.Person[]> Create_Person_Array()
        {
            return new global::PolyType.SourceGenModel.SourceGenEnumerableTypeShape<global::ConsoleApp1.Person[], global::ConsoleApp1.Person>
            {
                ElementType = Person,
                ConstructionStrategy = global::PolyType.Abstractions.CollectionConstructionStrategy.Span,
                DefaultConstructorFunc = null,
                EnumerableConstructorFunc = null,
                SpanConstructorFunc = static values => values.ToArray(),
                GetEnumerableFunc = static obj => obj,
                AddElementFunc = null,
                Rank = 1,
                Provider = this,
           };
        }
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace PolyType.SourceGenerator
{
    internal partial class GenerateShapeProvider
    {
        /// <summary>Gets the generated shape for specified type.</summary>
#nullable disable annotations // Use nullable-oblivious property type
        public global::PolyType.Abstractions.ITypeShape<string> String => _String ??= Create_String();
#nullable enable annotations // Use nullable-oblivious property type
        private global::PolyType.Abstractions.ITypeShape<string>? _String;

        private global::PolyType.Abstractions.ITypeShape<string> Create_String()
        {
            return new global::PolyType.SourceGenModel.SourceGenObjectTypeShape<string>
            {
                Provider = this,
                IsRecordType = false,
                IsTupleType = false,
                CreatePropertiesFunc = null,
                CreateConstructorFunc = null,
            };
        }
    }
}

Code and pdf at

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