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;
}
}
}