【发布时间】:2014-09-12 14:29:27
【问题描述】:
我有一个通用存储库实现,它允许传递选择器以声明实体主键属性:
public abstract class RepositoryBase<TEntity, TKey>
where TEntity : class
{
private readonly Func<TEntity, TKey> _keySelector;
protected Func<TEntity, TKey> KeySelector {
get {
return _keySelector;
}
}
protected RepositoryBase(Func<TEntity, TKey> selector) {
_keySelector = selector;
}
}
... 可以这样使用:
public class UserRepository : RepositoryBase<User, Guid>
{
public UserRepository()
: base((user) => user.Id)
{
}
}
我现在已经实现了一个 in memory 存储库 来做一些单元测试,我想为每个被持久化的实体生成一个新的身份。如果实体没有密钥的公共访问器,我创建了一个扩展方法来使用反射设置属性。
public static void SetProperty<T, TProperty>(this T instance, Expression<Func<T, TProperty>> selector,
TProperty newValue)
where T : class
{
if (instance == null)
throw new ArgumentNullException("instance");
if (selector == null)
throw new ArgumentNullException("selector");
var propertyInfo = selector.GetMember() as PropertyInfo;
if (propertyInfo == null)
throw new InvalidOperationException();
propertyInfo.SetValue(instance, newValue);
}
我现在的问题是:如何使用 KeySelector 作为 表达式 来设置主键值?有没有办法转换它?还是有更好的方法来实现我正在尝试的目标?
像这样?这有意义吗?:
protected override void AddItem(TEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
var id = default(TKey);
if (GetPrimaryKey(entity).Equals(default(TKey)))
{
id = _identifierGenerator.Generate();
entity.SetProperty(x => GetPrimaryKey(x), id); // <----
}
_items[id] = entity;
}
上面用到的一些方法:
方法'GetPrimaryKey'
public TKey GetPrimaryKey(TEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
return KeySelector(entity);
}
方法'GetMember'
public static MemberInfo GetMember<T, TProperty>(this Expression<Func<T, TProperty>> expression)
{
var memberExp = RemoveUnary(expression.Body);
return memberExp == null ? null : memberExp.Member;
}
方法'RemoveUnary'
private static MemberExpression RemoveUnary(Expression toUnwrap)
{
var unwrap = toUnwrap as UnaryExpression;
if (unwrap != null)
{
return unwrap.Operand as MemberExpression;
}
return toUnwrap as MemberExpression;
}
【问题讨论】:
-
你可以去
Expression<Func<T, TProperty>>到Func<T, TProperty>,但你不能去其他方式。你能把GetPrimaryKey的代码显示一下吗,也许可以修改为返回一个表达式。 -
您可以通过
x => func(x)轻松获得Expression<Func<T, TProperty>>,但它不适用于EnumerableQuery以外的任何提供者,因此对于您可能想要的任何东西都几乎没有用处做。 -
@ScottChamberlain 没问题,我已经在上面添加了。
-
@hvd 是否有更好的方法来解决我正在尝试的问题?
标签: c# lambda expression repository-pattern