Sto volendo creare un membroExpression conoscendo solo il nome del campo; per esempio:
public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>(string fieldName)
{
PropertyInfo fieldPropertyInfo;
fieldPropertyInfo = typeof(TModel).GetProperty(fieldName);
var entityParam = Expression.Parameter(typeof(TModel), "e"); // {e}
var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
var lambda = Expression.Lambda(columnExpr, entityParam) as Expression<Func<TModel, T>>; // {e => e.column}
return lambda;
}
Il problema con quanto sopra è che il tipo di campo deve essere fortemente digitato. Passando "oggetto" come tipo di campo non funziona. C'è un modo per generare questo? Anche Dynamic LINQ non sembra funzionare.
Esistono numerosi problemi con il tuo codice:
fieldName
, ma stai ottenendo una proprietà con esso. Expression.Lambda
non generico per generare l'espressione, che può scegliere un tipo di delegato inappropriato se l'argomento tipo T
passato al metodo non è uguale al tipo di proprietà. In questo caso, il as
gettato dall'espressione di ritorno di tipo del metodo non riuscirà e restituire null
. Soluzione: utilizzare il metodo Lambda
generico con gli argomenti di tipo appropriati. Nessuna fusione richiesta T
, ma non quando sono richieste conversioni più complicate come il pugilato / il sollevamento. Soluzione: utilizzare il metodo Expression.Convert
dove necessario. Ecco un aggiornamento del tuo esempio che risolve questi problemi:
public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>
(string propertyName)
{
var propertyInfo = typeof(TModel).GetProperty(propertyName);
var entityParam = Expression.Parameter(typeof(TModel), "e");
Expression columnExpr = Expression.Property(entityParam, propertyInfo);
if (propertyInfo.PropertyType != typeof(T))
columnExpr = Expression.Convert(columnExpr, typeof(T));
return Expression.Lambda<Func<TModel, T>>(columnExpr, entityParam);
}
Ciò renderà tutte le seguenti chiamate riuscite:
GenerateMemberExpression<FileInfo, string>("Name");
GenerateMemberExpression<string, int>("Length");
// Reference conversion
GenerateMemberExpression<FileInfo, object>("Name");
//Boxing conversion
GenerateMemberExpression<string, object>("Length");
//Lifted conversion
GenerateMemberExpression<string, int?>("Length");
Prova a convertire manualmente il valore del campo in caso di passaggio di un "oggetto". Per esempio:
var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
if (T.GetType().Equals(typeof(object)))
{
columnExpr = Expression.Convert(columnExpr, typeof(object));
}
Spero che questo ti possa aiutare.