Я использую некоторые сильно типизированные выражения, которые сериализуются, чтобы мой код пользовательского интерфейса имел строго типизированные выражения для сортировки и поиска. Они имеют тип Expression<Func<TModel,TProperty>>
и используются как таковые: SortOption.Field = (p => p.FirstName);
. Я получил эту работу отлично для этого простого случая.
Код, который я использую для разбора свойства FirstName, фактически повторно использует некоторые существующие функции в стороннем продукте, который мы используем, и он отлично работает, пока мы не начнем работать с глубоко вложенными свойствами ( SortOption.Field = (p => p.Address.State.Abbreviation);
). Этот код имеет несколько разных предположений о необходимости поддержки глубоко вложенных свойств.
Что касается этого кода, я действительно не понимаю его и вместо того, чтобы изменять этот код, я решил, что должен просто написать с нуля эту функциональность. Однако я не знаю, как это сделать. Я подозреваю, что мы можем сделать что-то лучше, чем делать ToString() и выполнять синтаксический анализ строк. Итак, какой хороший способ сделать это для обработки тривиальных и глубоко вложенных случаев?
Требования:
- Для выражения
p => p.FirstName
мне нужна строка"FirstName"
. - Для выражения
p => p.Address.State.Abbreviation
мне нужна строка"Address.State.Abbreviation"
Хотя это не важно для ответа на мой вопрос, я подозреваю, что мой код сериализации/десериализации может быть полезен кому-то другому, который находит этот вопрос в будущем, поэтому он ниже. Опять же, этот код не важен для вопроса - я просто подумал, что это может помочь кому-то. Обратите внимание, что DynamicExpression.ParseLambda
поступает из Динамический LINQ и Property.PropertyToString()
, о чем идет речь.
/// <summary>
/// This defines a framework to pass, across serialized tiers, sorting logic to be performed.
/// </summary>
/// <typeparam name="TModel">This is the object type that you are filtering.</typeparam>
/// <typeparam name="TProperty">This is the property on the object that you are filtering.</typeparam>
[Serializable]
public class SortOption<TModel, TProperty> : ISerializable where TModel : class
{
/// <summary>
/// Convenience constructor.
/// </summary>
/// <param name="property">The property to sort.</param>
/// <param name="isAscending">Indicates if the sorting should be ascending or descending</param>
/// <param name="priority">Indicates the sorting priority where 0 is a higher priority than 10.</param>
public SortOption(Expression<Func<TModel, TProperty>> property, bool isAscending = true, int priority = 0)
{
Property = property;
IsAscending = isAscending;
Priority = priority;
}
/// <summary>
/// Default Constructor.
/// </summary>
public SortOption()
: this(null)
{
}
/// <summary>
/// This is the field on the object to filter.
/// </summary>
public Expression<Func<TModel, TProperty>> Property { get; set; }
/// <summary>
/// This indicates if the sorting should be ascending or descending.
/// </summary>
public bool IsAscending { get; set; }
/// <summary>
/// This indicates the sorting priority where 0 is a higher priority than 10.
/// </summary>
public int Priority { get; set; }
#region Implementation of ISerializable
/// <summary>
/// This is the constructor called when deserializing a SortOption.
/// </summary>
protected SortOption(SerializationInfo info, StreamingContext context)
{
IsAscending = info.GetBoolean("IsAscending");
Priority = info.GetInt32("Priority");
// We just persisted this by the PropertyName. So let rebuild the Lambda Expression from that.
Property = DynamicExpression.ParseLambda<TModel, TProperty>(info.GetString("Property"), default(TModel), default(TProperty));
}
/// <summary>
/// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data. </param>
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization. </param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// Just stick the property name in there. We'll rebuild the expression based on that on the other end.
info.AddValue("Property", Property.PropertyToString());
info.AddValue("IsAscending", IsAscending);
info.AddValue("Priority", Priority);
}
#endregion
}