feat: added primitive serialization

This commit is contained in:
Syntriax 2025-04-17 22:21:12 +03:00
parent c205e710bc
commit eb454a471c
15 changed files with 454 additions and 189 deletions

View File

@ -0,0 +1,41 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class AABBConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(AABB);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(AABB.LowerBoundary)) != 0)
throw new ArgumentException($"{nameof(AABB)} mapping must start with {nameof(AABB.LowerBoundary)}");
Vector2D lowerBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(AABB.UpperBoundary)) != 0)
throw new ArgumentException($"{nameof(AABB)} mapping must end with {nameof(AABB.UpperBoundary)}");
Vector2D upperBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
parser.Consume<MappingEnd>();
return new AABB(lowerBoundary, upperBoundary);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
AABB aabb = (AABB)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(AABB.LowerBoundary)));
serializer(aabb.LowerBoundary, typeof(Vector2D));
emitter.Emit(new Scalar(nameof(AABB.UpperBoundary)));
serializer(aabb.UpperBoundary, typeof(Vector2D));
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,5 @@
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public interface IEngineTypeYamlConverter : IYamlTypeConverter;

View File

@ -0,0 +1,41 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class CircleConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(Circle);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Circle.Center)) != 0)
throw new ArgumentException($"{nameof(Circle)} mapping must start with {nameof(Circle.Center)}");
Vector2D lowerBoundary = (Vector2D)rootDeserializer(typeof(Vector2D))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Circle.Radius)) != 0)
throw new ArgumentException($"{nameof(Circle)} mapping must end with {nameof(Circle.Radius)}");
float radius = (float)rootDeserializer(typeof(float))!;
parser.Consume<MappingEnd>();
return new Circle(lowerBoundary, radius);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Circle circle = (Circle)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Circle.Center)));
serializer(circle.Center, typeof(Vector2D));
emitter.Emit(new Scalar(nameof(Circle.Radius)));
serializer(circle.Radius, typeof(float));
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,41 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class Line2DConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(Line2D);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2D.From)) != 0)
throw new ArgumentException($"{nameof(Line2D)} mapping must start with {nameof(Line2D.From)}");
Vector2D from = (Vector2D)rootDeserializer(typeof(Vector2D))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2D.To)) != 0)
throw new ArgumentException($"{nameof(Line2D)} mapping must end with {nameof(Line2D.To)}");
Vector2D to = (Vector2D)rootDeserializer(typeof(Vector2D))!;
parser.Consume<MappingEnd>();
return new Line2D(from, to);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Line2D line2D = (Line2D)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Line2D.From)));
serializer(line2D.From, typeof(Vector2D));
emitter.Emit(new Scalar(nameof(Line2D.To)));
serializer(line2D.To, typeof(Vector2D));
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,41 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class Line2DEquationConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(Line2DEquation);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2DEquation.Slope)) != 0)
throw new ArgumentException($"{nameof(Line2DEquation)} mapping must start with {nameof(Line2DEquation.Slope)}");
float slope = (float)rootDeserializer(typeof(float))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Line2DEquation.OffsetY)) != 0)
throw new ArgumentException($"{nameof(Line2DEquation)} mapping must end with {nameof(Line2DEquation.OffsetY)}");
float offset = (float)rootDeserializer(typeof(float))!;
parser.Consume<MappingEnd>();
return new Line2DEquation(slope, offset);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Line2DEquation line2DEquation = (Line2DEquation)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Line2DEquation.Slope)));
serializer(line2DEquation.Slope, typeof(float));
emitter.Emit(new Scalar(nameof(Line2DEquation.OffsetY)));
serializer(line2DEquation.OffsetY, typeof(float));
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,41 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class Projection1DConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(Projection1D);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Projection1D.Min)) != 0)
throw new ArgumentException($"{nameof(Projection1D)} mapping must start with {nameof(Projection1D.Min)}");
float min = (float)rootDeserializer(typeof(float))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Projection1D.Max)) != 0)
throw new ArgumentException($"{nameof(Projection1D)} mapping must end with {nameof(Projection1D.Max)}");
float max = (float)rootDeserializer(typeof(float))!;
parser.Consume<MappingEnd>();
return new Projection1D(min, max);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Projection1D projection1D = (Projection1D)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Projection1D.Min)));
serializer(projection1D.Min, typeof(float));
emitter.Emit(new Scalar(nameof(Projection1D.Max)));
serializer(projection1D.Max, typeof(float));
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,28 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class QuaternionConverter : IEngineTypeYamlConverter
{
private static readonly int SUBSTRING_START_LENGTH = nameof(Quaternion).Length + 1;
public bool Accepts(Type type) => type == typeof(Quaternion);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
string value = parser.Consume<Scalar>().Value;
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
string[] values = insideParenthesis.Split(", ");
return new Quaternion(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3]));
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Quaternion quaternion = (Quaternion)value!;
emitter.Emit(new Scalar($"{nameof(Quaternion)}({quaternion.X}, {quaternion.Y}, {quaternion.Z}, {quaternion.W})"));
}
}

View File

@ -0,0 +1,47 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class Shape2DConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(Shape2D);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Shape2D.Vertices)) != 0)
throw new ArgumentException($"{nameof(Shape2D)} mapping have a {nameof(Shape2D.Vertices)}");
parser.Consume<SequenceStart>();
List<Vector2D> vertices = [];
while (!parser.TryConsume<SequenceEnd>(out _))
{
Vector2D vertex = (Vector2D)rootDeserializer(typeof(Vector2D))!;
vertices.Add(vertex);
}
parser.Consume<MappingEnd>();
return new Shape2D(vertices);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Shape2D shape2D = (Shape2D)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Shape2D.Vertices)));
emitter.Emit(new SequenceStart(anchor: null, tag: null, isImplicit: false, style: SequenceStyle.Block));
foreach (Vector2D vertex in shape2D.Vertices)
serializer(vertex, typeof(Vector2D));
emitter.Emit(new SequenceEnd());
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,47 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class TriangleConverter : IEngineTypeYamlConverter
{
public bool Accepts(Type type) => type == typeof(Triangle);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.A)) != 0)
throw new ArgumentException($"{nameof(Triangle)} mapping must start with {nameof(Triangle.A)}");
Vector2D a = (Vector2D)rootDeserializer(typeof(Vector2D))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.B)) != 0)
throw new ArgumentException($"{nameof(Triangle)} mapping must have {nameof(Triangle.B)} after {nameof(Triangle.A)}");
Vector2D b = (Vector2D)rootDeserializer(typeof(Vector2D))!;
if (parser.Consume<Scalar>().Value.CompareTo(nameof(Triangle.C)) != 0)
throw new ArgumentException($"{nameof(Triangle)} mapping must end with {nameof(Triangle.C)}");
Vector2D c = (Vector2D)rootDeserializer(typeof(Vector2D))!;
parser.Consume<MappingEnd>();
return new Triangle(a, b, c);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Triangle aabb = (Triangle)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Triangle.A)));
serializer(aabb.A, typeof(Vector2D));
emitter.Emit(new Scalar(nameof(Triangle.B)));
serializer(aabb.B, typeof(Vector2D));
emitter.Emit(new Scalar(nameof(Triangle.C)));
serializer(aabb.C, typeof(Vector2D));
emitter.Emit(new MappingEnd());
}
}

View File

@ -0,0 +1,28 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class Vector2DConverter : IEngineTypeYamlConverter
{
private static readonly int SUBSTRING_START_LENGTH = nameof(Vector2D).Length + 1;
public bool Accepts(Type type) => type == typeof(Vector2D);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
string value = parser.Consume<Scalar>().Value;
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
string[] values = insideParenthesis.Split(", ");
return new Vector2D(float.Parse(values[0]), float.Parse(values[1]));
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Vector2D vector2D = (Vector2D)value!;
emitter.Emit(new Scalar($"{nameof(Vector2D)}({vector2D.X}, {vector2D.Y})"));
}
}

View File

@ -0,0 +1,28 @@
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Syntriax.Engine.Serialization;
public class Vector3DConverter : IEngineTypeYamlConverter
{
private static readonly int SUBSTRING_START_LENGTH = nameof(Vector3D).Length + 1;
public bool Accepts(Type type) => type == typeof(Vector3D);
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
string value = parser.Consume<Scalar>().Value;
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
string[] values = insideParenthesis.Split(", ");
return new Vector3D(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]));
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Vector3D vector3D = (Vector3D)value!;
emitter.Emit(new Scalar($"{nameof(Vector3D)}({vector3D.X}, {vector3D.Y}, {vector3D.Z})"));
}
}

View File

@ -1,172 +0,0 @@
using System.Collections;
using System.Reflection;
using Syntriax.Engine.Core;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace Syntriax.Engine.Serialization;
public class Vector2DConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return type == typeof(Vector2D);
}
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
parser.Consume<MappingStart>();
float x = 0f;
float y = 0f;
while (!parser.TryConsume<MappingEnd>(out _))
{
string key = parser.Consume<Scalar>().Value;
string value = parser.Consume<Scalar>().Value;
if (key.CompareTo(nameof(Vector2D.X)) == 0) x = float.Parse(value);
if (key.CompareTo(nameof(Vector2D.Y)) == 0) y = float.Parse(value);
}
return new Vector2D(x, y);
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
Vector2D vector2D = (Vector2D)value!;
emitter.Emit(new MappingStart());
emitter.Emit(new Scalar(nameof(Vector2D.X)));
emitter.Emit(new Scalar(vector2D.X.ToString()));
emitter.Emit(new Scalar(nameof(Vector2D.Y)));
emitter.Emit(new Scalar(vector2D.Y.ToString()));
emitter.Emit(new MappingEnd());
}
}
public class EntityConverter : IYamlTypeConverter
{
private static readonly ISerializer serializer = new SerializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.DisableAliases()
.Build();
private static readonly IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.Build();
public bool Accepts(Type type)
{
bool v = typeof(IEntity).IsAssignableFrom(type);
return v;
}
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
string? id = null;
parser.Consume<MappingStart>();
while (!parser.TryConsume<MappingEnd>(out _))
{
string key = parser.Consume<Scalar>().Value;
string value = parser.Consume<Scalar>().Value;
if (key.CompareTo(nameof(EntityReference.Id)) == 0)
id = value;
}
return new EntityReference() { Id = id };
}
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
if (value is not IEntity entity)
return;
var typeData = GetTypeData(type);
emitter.Emit(new MappingStart());
foreach (var fieldInfo in typeData.Fields)
{
if (fieldInfo.GetCustomAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>() != null)
continue;
emitter.Emit(new Scalar(fieldInfo.Name));
var fieldValue = fieldInfo.GetValue(entity);
EmitValue(fieldValue, fieldInfo.FieldType, emitter, serializer);
}
foreach (var propertyInfo in typeData.Properties)
{
emitter.Emit(new Scalar(propertyInfo.Name));
var propValue = propertyInfo.GetValue(entity);
EmitValue(propValue, propertyInfo.PropertyType, emitter, serializer);
}
emitter.Emit(new MappingEnd());
}
private void EmitValue(object? value, Type declaredType, IEmitter emitter, ObjectSerializer serializer)
{
if (value is null)
{
emitter.Emit(new Scalar("null"));
return;
}
if (value is IEntity singleEntity && !IsEnumerable(declaredType))
{
emitter.Emit(new Scalar(singleEntity.Id));
return;
}
if (IsEnumerable(declaredType) && value is System.Collections.IEnumerable list)
{
emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block));
foreach (var item in list)
{
if (item is IEntity itemEntity)
emitter.Emit(new Scalar(itemEntity.Id));
else
serializer(item); // fallback for non-entity items
}
emitter.Emit(new SequenceEnd());
return;
}
// fallback
serializer(value);
}
private static TypeData GetTypeData(Type objectType)
{
IEnumerable<System.Reflection.EventInfo> eventInfos = objectType.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.OrderBy(ei => ei.Name)
.AsEnumerable();
IEnumerable<FieldInfo> fieldInfos = objectType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Where(fi => !eventInfos.Any(ei => fi.Name.CompareTo(ei.Name) == 0))
.OrderBy(ei => ei.Name) //ei => ei.FieldType.IsPrimitive || ei.FieldType == typeof(string))
// .ThenByDescending(ei => ei.Name)
.AsEnumerable();
IEnumerable<PropertyInfo> propertyInfos = objectType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Where(pi => pi.SetMethod is not null)
.OrderBy(ei => ei.Name)// ei => ei.PropertyType.IsPrimitive || ei.PropertyType == typeof(string))
// .ThenByDescending(ei => ei.Name)
.AsEnumerable();
return new TypeData(eventInfos, fieldInfos, propertyInfos);
}
private static bool IsEnumerable(Type type)
{
return typeof(System.Collections.IEnumerable).IsAssignableFrom(type) && type != typeof(string);
}
private record struct TypeData(IEnumerable<System.Reflection.EventInfo> Events, IEnumerable<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
{
public static implicit operator (IEnumerable<System.Reflection.EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Events, value.Fields, value.Properties);
public static implicit operator TypeData((IEnumerable<System.Reflection.EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new TypeData(value.events, value.fields, value.properties);
}
}

View File

@ -1,6 +0,0 @@
namespace Syntriax.Engine.Serialization;
public class EntityReference
{
public string Id { get; set; }
}

View File

@ -1,3 +1,4 @@
using System.Reflection;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
@ -5,24 +6,47 @@ namespace Syntriax.Engine.Serialization;
public static class Serializer
{
private static readonly ISerializer serializer = new SerializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.DisableAliases()
.WithTypeConverter(new EntityConverter())
.WithTypeConverter(new Vector2DConverter())
.Build();
private static readonly ISerializer serializer = GetSerializer();
private static ISerializer GetSerializer()
{
SerializerBuilder serializerBuilder = new SerializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.DisableAliases();
private static readonly IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.WithTypeConverter(new EntityConverter())
.WithTypeConverter(new Vector2DConverter())
.Build();
foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
return serializerBuilder.Build();
}
private static readonly IDeserializer deserializer = GetDeserializer();
private static IDeserializer GetDeserializer()
{
DeserializerBuilder serializerBuilder = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance);
foreach (IEngineTypeYamlConverter typeConverter in GetEngineYamlTypeConverters())
serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
return serializerBuilder.Build();
}
private static IEnumerable<IEngineTypeYamlConverter> GetEngineYamlTypeConverters()
{
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(IEngineTypeYamlConverter).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract))
yield return (Activator.CreateInstance(type) as IEngineTypeYamlConverter)!;
}
public static string Serialize(object instance)
{
return serializer.Serialize(instance);
}
public static object Deserialize(string yaml)
{
return deserializer.Deserialize(yaml)!;
}
public static T Deserialize<T>(string yaml)
{
return deserializer.Deserialize<T>(yaml);

View File

@ -0,0 +1,31 @@
using System.Reflection;
namespace Syntriax.Engine.Serialization;
internal static class Utils
{
internal static TypeData GetTypeData(this Type type)
{
IEnumerable<EventInfo> eventInfos = type.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.OrderBy(ei => ei.Name)
.AsEnumerable();
IEnumerable<FieldInfo> fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Where(fi => !eventInfos.Any(ei => fi.Name.CompareTo(ei.Name) == 0))
.OrderBy(ei => ei.Name) //ei => ei.FieldType.IsPrimitive || ei.FieldType == typeof(string))
// .ThenByDescending(ei => ei.Name)
.AsEnumerable();
IEnumerable<PropertyInfo> propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Where(pi => pi.SetMethod is not null)
.OrderBy(ei => ei.Name)// ei => ei.PropertyType.IsPrimitive || ei.PropertyType == typeof(string))
// .ThenByDescending(ei => ei.Name)
.AsEnumerable();
return new TypeData(eventInfos, fieldInfos, propertyInfos);
}
}
internal record struct TypeData(IEnumerable<EventInfo> Events, IEnumerable<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
{
public static implicit operator (IEnumerable<EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Events, value.Fields, value.Properties);
public static implicit operator TypeData((IEnumerable<EventInfo> events, IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new TypeData(value.events, value.fields, value.properties);
}