AdamsLair / duality

a 2D Game Development Framework
https://adamslair.github.io/duality
MIT License
1.4k stars 290 forks source link

Make serializer work nicely with autoproperties #864

Open Barsonax opened 4 years ago

Barsonax commented 4 years ago

Summary

Currently we try to avoid using auto properties because when serializing a instance the serializer will use the name of the backing fields which have a ugly name like <Foo>k__BackingField.

Consider changing the serializers to understand the relationship between the backing fields and the properties to allow them to handle these in a nicer way

Analysis

Simple example of getting the backingfield or the autoproperty. No idea if this is stable enough, needs more research.

        const string prefix = "<";
        const string suffix = ">k__BackingField";

        public static FieldInfo GetBackingField(PropertyInfo propertyInfo)
        {
            var backingFieldName = $"{prefix}{propertyInfo.Name}{suffix}";
            return propertyInfo.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).FirstOrDefault(x => x.Name == backingFieldName && x.IsDefined(typeof(CompilerGeneratedAttribute)));
        }

        public static PropertyInfo GetAutoProperty(FieldInfo field)
        {
            if (field.Name.StartsWith(prefix) && field.Name.EndsWith(suffix) && field.IsDefined(typeof(CompilerGeneratedAttribute), true))
            {
                var propertyName = field.Name[prefix.Length..^suffix.Length];
                if (propertyName != null)
                {
                    return field.DeclaringType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
                             .Where(x => x.SetMethod != null && x.SetMethod.IsDefined(typeof(CompilerGeneratedAttribute)))
                             .Where(x => x.GetMethod != null && x.GetMethod.IsDefined(typeof(CompilerGeneratedAttribute)))
                             .FirstOrDefault(x => x.Name == propertyName);
                }
            }
            return null;
        }
ilexp commented 3 years ago

Some notes:

Barsonax commented 3 years ago

There appears to be a CompilerGenerated attribute on both the properties and fields, which we could potentially use to filter out candidates for any matching.

Oh also on the property? Thats nice. Can make it quite robust then by just checking if theres a attribute on both sides.

EDIT: updated the example on this.

ilexp commented 3 years ago

Not the property itself, but its internal getter and setter methods get one. Still, could be useful enough for some sort of verification.