using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.AspNetCore.Components;
namespace AntDesign.Core.HashCodes
{
///
/// Represents a parameter descriptor for a component
///
///
class ParameterDescriptor
{
private readonly bool _isParameter;
private readonly HashCodeProvider _hashCodeProvider;
private readonly Func _getter;
///
/// Gets a description of all the parameters of the component
///
public static readonly ParameterDescriptor[] Descriptors
= typeof(TComponent)
.GetProperties()
.Select(item => new ParameterDescriptor(item))
.Where(item => item._isParameter)
.ToArray();
///
/// A parameter descriptor for a component
///
/// 属性类型
private ParameterDescriptor(PropertyInfo property)
{
if (property == null)
{
throw new ArgumentNullException(nameof(property));
}
this._isParameter = IsEventCallBack(property) == false
|| property.IsDefined(typeof(ParameterAttribute))
|| property.IsDefined(typeof(CascadingParameterAttribute));
if (this._isParameter == true)
{
this._getter = CreateGetFunc(property);
this._hashCodeProvider = HashCodeProvider.Create(property.PropertyType);
}
}
///
/// Check whether it is of type EventCallback
///
///
///
private static bool IsEventCallBack(PropertyInfo property)
{
var type = property.PropertyType;
if (type == typeof(EventCallback))
{
return true;
}
if (type.IsGenericType == true)
{
return type.GetGenericTypeDefinition() == typeof(EventCallback<>);
}
return false;
}
///
/// Create the get delegate for the property
///
/// Property
///
private static Func CreateGetFunc(PropertyInfo property)
{
// (TComponent component) => (object)(component.Property)
var componentType = typeof(TComponent);
var parameter = Expression.Parameter(componentType);
var member = Expression.Property(parameter, property);
var body = Expression.Convert(member, typeof(object));
return Expression.Lambda>(body, parameter).Compile();
}
///
/// Returns the hash of the parameter value
///
/// 组件
///
///
public int GetValueHashCode(TComponent component)
{
if (this._isParameter == false)
{
throw new NotSupportedException();
}
var value = this._getter(component);
return this._hashCodeProvider.GetHashCode(value);
}
}
}