/// <summary> /// Validates, creates and compiles the property expression; whilst also determinig the property friendly <see cref="PropertyExpression{TEntity, TProperty}.Text"/>. /// </summary> /// <param name="propertyExpression">The <see cref="Expression"/> to reference the entity property.</param> /// <param name="probeForJsonRefDataSidProperties">Indicates whether to probe for the <see cref="JsonPropertyAttribute"/> via alternate <c>Sid</c> or <c>Sids</c> properties as implemented for reference data.</param> /// <returns>A <see cref="PropertyExpression{TEntity, TProperty}"/> which contains (in order) the compiled <see cref="System.Func{TEntity, TProperty}"/>, member name and resulting property text.</returns> public static PropertyExpression <TEntity, TProperty> Create <TEntity, TProperty>(Expression <Func <TEntity, TProperty> > propertyExpression, bool probeForJsonRefDataSidProperties = false) { return(PropertyExpression <TEntity, TProperty> .CreateInternal(Check.NotNull(propertyExpression, nameof(propertyExpression)), probeForJsonRefDataSidProperties)); }
/// <summary> /// Validates, creates and compiles the property expression; whilst also determinig the property friendly <see cref="Text"/>. /// </summary> /// <param name="propertyExpression">The <see cref="Expression"/> to reference the entity property.</param> /// <param name="probeForJsonRefDataSidProperties">Indicates whether to probe for the <see cref="T:JsonPropertyAttribute"/> via alternate <c>Sid</c> or <c>Sids</c> properties as implemented for reference data.</param> /// <returns>A <see cref="PropertyExpression{TEntity, TProperty}"/> which contains (in order) the compiled <see cref="System.Func{TEntity, TProperty}"/>, member name and resulting property text.</returns> public static PropertyExpression <TEntity, TProperty> Create(Expression <Func <TEntity, TProperty> > propertyExpression, bool probeForJsonRefDataSidProperties = false) { if (propertyExpression == null) { throw new ArgumentNullException("propertyExpression"); } if (propertyExpression.Body.NodeType != ExpressionType.MemberAccess) { throw new InvalidOperationException("Only Member access expressions are supported."); } var me = (MemberExpression)propertyExpression.Body; // Check cache and reuse as this is an expensive operation. var key = new ExpressionKey { Type = me.Member.DeclaringType, Name = me.Member.Name, ProbeForJsonRefDataSidProperties = probeForJsonRefDataSidProperties }; if (_expressions.ContainsKey(key)) { return(_expressions[key]); } if (me.Member.MemberType != MemberTypes.Property) { throw new InvalidOperationException("Expression results in a Member that is not a Property."); } if (!me.Member.DeclaringType.GetTypeInfo().IsAssignableFrom(typeof(TEntity).GetTypeInfo())) { throw new InvalidOperationException("Expression results in a Member for a different Entity class."); } var pe = new PropertyExpression <TEntity, TProperty>() { Name = me.Member.Name }; // Either get the friendly text from a corresponding DisplayTextAttribute or split the PascalCase member name into friendlier sentence case text. DisplayAttribute ca = me.Member.GetCustomAttribute <DisplayAttribute>(true); pe.Text = ca == null?Beef.CodeGen.CodeGenerator.ToSentenceCase(pe.Name) : ca.Name; // Get the JSON property name. JsonPropertyAttribute jpa = me.Member.GetCustomAttribute <JsonPropertyAttribute>(true); if (jpa == null && probeForJsonRefDataSidProperties) { // Probe corresponding Sid or Sids properties for value (using the standardised naming convention). var pi = me.Member.DeclaringType.GetProperty($"{pe.Name}Sid"); if (pi == null) { pi = me.Member.DeclaringType.GetProperty($"{pe.Name}Sids"); } if (pi != null) { jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(true); } } pe.JsonPropertyAttribute = jpa; pe.JsonName = jpa == null ? pe.Name : jpa.PropertyName; // Compile the expression. pe._func = propertyExpression.Compile(); // Recheck cache and use/update accordingly. lock (_lock) { if (_expressions.ContainsKey(key)) { return(_expressions[key]); } _expressions.Add(key, pe); } return(pe); }