我有以下類,對此用法不重要。最重要的是方法SetCacheItemSelector這需要一個參數,即項目佔實體AccountCacheDTO一個選擇表達式:動態選擇投影表達式
public class AccountRepositoryCache : RepositoryCache<Account, AccountCacheDTO>
{
public AccountRepositoryCache()
{
SetCacheItemSelector(x => new AccountCacheDTO
{
Id = x.Id,
Login = x.Login
});
}
}
所以此方法的簽名是:
public void SetCacheItemSelector(Expression<Func<TEntity, TCacheItem>> selector)
在這種情況下,TEntity是Account類,並且TCacheItem是AccountCacheDTO類。
是否有一種方法可以使用反射動態地爲Account類和AccountCacheDTO類匹配的所有屬性構建select表達式?
目標是有方法應該是這樣的:
public Expression<Func<TEntity, TCacheItem>> BuildSelector<TEntity, TCacheItem>()
{
... // implementation with reflection goes here
}
編輯:
這裏是最終實現(幾乎一樣接受的答案):
public static Expression<Func<TSource, TTarget>> BuildSelector<TSource, TTarget>()
{
Type targetType = typeof(TTarget);
Type sourceType = typeof(TSource);
ParameterExpression parameterExpression = Expression.Parameter(sourceType, "source");
List<MemberBinding> bindings = new List<MemberBinding>();
foreach (PropertyInfo sourceProperty in sourceType.GetProperties().Where(x => x.CanRead))
{
PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name);
if (targetProperty != null && targetProperty.CanWrite && targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
{
MemberExpression propertyExpression = Expression.Property(parameterExpression, sourceProperty);
bindings.Add(Expression.Bind(targetProperty, propertyExpression));
}
}
NewExpression newExpression = Expression.New(targetType);
Expression initializer = Expression.MemberInit(newExpression, bindings);
return Expression.Lambda<Func<TSource, TTarget>>(initializer, parameterExpression);
}
爲什麼'表達式>'而不是簡單的'Func <...>''? 'Expression <>'將產生一個抽象語法樹,但不是一個可執行的委託。 –
@ OlivierJacot-Descombes由於'Expression'允許它在LINQ查詢提供程序中使用。 – Servy
@Servy實際上,我打算將這一點與LINQ 2實體提供者一起使用。 –