using System; using System.Linq.Expressions; using System.Reflection; namespace Swan.Reflection { /// /// The concrete and hidden implementation of the implementation. /// /// internal sealed class PropertyInfoProxy : IPropertyProxy { private readonly Func? _getter; private readonly Action? _setter; /// /// Initializes a new instance of the class. /// /// Type of the declaring. /// The property information. public PropertyInfoProxy(Type declaringType, PropertyInfo propertyInfo) { Property = propertyInfo; EnclosingType = declaringType; _getter = CreateLambdaGetter(declaringType, propertyInfo); _setter = CreateLambdaSetter(declaringType, propertyInfo); } /// public PropertyInfo Property { get; } /// public Type EnclosingType { get; } /// public string Name => Property.Name; /// public Type PropertyType => Property.PropertyType; /// public object? GetValue(object instance) => _getter?.Invoke(instance); /// public void SetValue(object instance, object? value) => _setter?.Invoke(instance, value); private static Func? CreateLambdaGetter(Type instanceType, PropertyInfo propertyInfo) { if (!propertyInfo.CanRead) return null; var instanceParameter = Expression.Parameter(typeof(object), "instance"); var typedInstance = Expression.Convert(instanceParameter, instanceType); var property = Expression.Property(typedInstance, propertyInfo); var convert = Expression.Convert(property, typeof(object)); var dynamicGetter = (Func)Expression.Lambda(convert, instanceParameter).Compile(); return dynamicGetter; } private static Action? CreateLambdaSetter(Type instanceType, PropertyInfo propertyInfo) { if (!propertyInfo.CanWrite) return null; var instanceParameter = Expression.Parameter(typeof(object), "instance"); var valueParameter = Expression.Parameter(typeof(object), "value"); var typedInstance = Expression.Convert(instanceParameter, instanceType); var property = Expression.Property(typedInstance, propertyInfo); var propertyValue = Expression.Convert(valueParameter, propertyInfo.PropertyType); var body = Expression.Assign(property, propertyValue); var dynamicSetter = Expression.Lambda>(body, instanceParameter, valueParameter).Compile(); return dynamicSetter; } } }