Utilizo algunas expresiones fuertemente tipadas que se serializan para permitir que mi código de la UI tenga una clasificación fuerte y expresiones de búsqueda. Estos son del tipo Expression<Func<TModel,TProperty>>
y se usan como tales: SortOption.Field = (p => p.FirstName);
. He conseguido que esto funcione perfectamente para este caso simple.Obtenga la propiedad, como una cadena, de una expresión <Func <TModel, TProperty >>
El código que estoy usando para analizar la propiedad "FirstName" está reutilizando alguna funcionalidad existente en un producto de terceros que usamos y funciona muy bien, hasta que comenzamos a trabajar con propiedades anidadas (SortOption.Field = (p => p.Address.State.Abbreviation);
). Este código tiene algunas suposiciones muy diferentes sobre la necesidad de admitir propiedades profundamente anidadas.
En cuanto a lo que hace este código, realmente no lo entiendo y en lugar de cambiar ese código, pensé que debería escribir desde cero esta funcionalidad. Sin embargo, no sé de una buena forma para hacer esto. Sospecho que podemos hacer algo mejor que hacer un ToString() y realizar un análisis sintáctico de cadenas. Entonces, ¿cuál es una buena manera de hacer esto para manejar los casos triviales y profundamente anidados?
Requisitos:
- Dada la expresión
p => p.FirstName
que necesitan una serie de"FirstName"
. - Teniendo en cuenta la expresión
p => p.Address.State.Abbreviation
necesito una cadena de"Address.State.Abbreviation"
Si bien no es importante para una respuesta a mi pregunta, sospecho que mi código de serialización/deserialización podría ser útil a alguien que también se encuentra esta pregunta en el futuro, por lo que está abajo. De nuevo, este código no es importante para la pregunta, solo pensé que podría ayudar a alguien. Tenga en cuenta que DynamicExpression.ParseLambda
proviene del material Dynamic LINQ y Property.PropertyToString()
es de lo que se trata esta pregunta.
/// <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's 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
}
posible duplicado de [C#: obtención de nombres de propiedades en una cadena desde la expresión lambda] (http://stackoverflow.com/questions/1667408/c-getting-names-of-properties-in-a-chain-from -lambda-expression) – nawfal
@nawfal Esa pregunta va tras algo ligeramente diferente que también tiene problemas ligeramente diferentes. Quieren dividir cada parte del espacio de nombres en cadenas separadas.Lo quería en una sola cuerda. Además, las respuestas a esa pregunta no * manejan unboxing (object -> int), que era parte de mi problema. Entonces esta pregunta no es un duplicado de esa pregunta. – Jaxidian
Jaxidian, ya veo, pero aún así es un duplicado para mí. La diferencia de la matriz de cadenas devuelta y el mismo resultado devuelto como una sola cadena unida no es un diferenciador, teniendo en cuenta que ese no es el problema más grande en absoluto. Sí, tenía una respuesta incompleta, tienes razón para preguntarla nuevamente. Pero dado que las respuestas se modifican allí, podemos cerrarlo ahora, creo. – nawfal