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