C# 表达式<;Func<;T、 布尔>&燃气轮机;谓词有两种类型
我有WebAPI方法:C# 表达式<;Func<;T、 布尔>&燃气轮机;谓词有两种类型,c#,C#,我有WebAPI方法: public async Task<MerchantViewModel> Get(string externalId) { return await _service.Get(m => m.ExternalId == externalId); } 其中T为商户 现在我想做一些类似的事情: public async Task<MerchantViewModel> Get(Expression<Func&l
public async Task<MerchantViewModel> Get(string externalId)
{
return await _service.Get(m => m.ExternalId == externalId);
}
其中T
为商户
现在我想做一些类似的事情:
public async Task<MerchantViewModel> Get(Expression<Func<MerchantViewModel, bool>> predicate)
{
var domainMerchant = this._repository.GetItemAsync(predicate)
}
公共异步任务Get(表达式谓词)
{
var domainMerchant=this.\u repository.GetItemAsync(谓词)
}
我怎么能做到
Merchant和MerchantViewModel具有相同的属性。ViewModel还有更多功能 解决方案1 首先,将
MerchantViewModel
和Merchant
之间重叠的属性抽象到一个接口中:
public IMerchantFilter
{
public string ExternalId { get; set; }
...
}
然后让MerchantViewModel
和Merchant
从该接口继承
public MerchantViewModel : IMerchantFilter
{
public string ExternalId { get; set; }
...
}
public Merchant : IMerchantFilter
{
public string ExternalId { get; set; }
...
}
使用谓词签名中的接口:
public class MerchantService : IMerchantService
{
public Task<MerchantViewModel> Get(Expression<Func<IMerchantFilter, bool>> predicate)
{
...
}
...
}
public class MerchantRepository : ...
{
public async Task<IEnumerable<Merchant>> GetItemsAsync(
Expression<Func<IMerchantFilter, bool>> predicate = null)
{
...
}
...
}
公共类商品服务:IMerchantService
{
公共任务Get(表达式谓词)
{
...
}
...
}
公共类商品仓:。。。
{
公共异步任务GetItemsAsync(
表达式谓词=null)
{
...
}
...
}
解决方案2 不同的解决方案(基于)可以在类型之间映射谓词:
using System;
using System.Linq.Expressions;
public static class PredicateMapper
{
public static Expression<Func<TTo, bool>> CastParameter<TFrom, TTo>(
this Expression<Func<TFrom, bool>> predicate)
{
var parameter = Expression.Parameter(typeof(TTo));
var body = new ParameterReplacer<TTo>(parameter).Visit(predicate.Body);
return Expression.Lambda<Func<TTo, bool>>(body, parameter);
}
private class ParameterReplacer<TTo> : ExpressionVisitor
{
private readonly ParameterExpression parameter;
public ParameterReplacer(ParameterExpression parameter)
{
this.parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return this.parameter;
}
protected override Expression VisitMember(MemberExpression node)
{
var matchingMember = typeof(TTo).GetProperty(node.Member.Name);
return Expression.Property(this.Visit(node.Expression), matchingMember);
}
}
}
使用系统;
使用System.Linq.Expressions;
公共静态类谓词映射器
{
公共静态表达式参数(
此表达式(谓词)
{
var参数=表达式参数(typeof(TTo));
var body=新参数replacer(parameter.Visit)(predicate.body);
返回表达式.Lambda(主体,参数);
}
私有类参数替换器:ExpressionVisitor
{
私有只读参数expression参数;
公共参数替换器(ParameterExpression参数)
{
this.parameter=参数;
}
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
返回此参数;
}
受保护的重写表达式VisitMember(MemberExpression节点)
{
var matchingMember=typeof(TTo).GetProperty(node.Member.Name);
返回Expression.Property(this.Visit(node.Expression),matchingMember);
}
}
}
在您的场景中,用法如下所示:
public async Task<MerchantViewModel> Get(
Expression<Func<MerchantViewModel, bool>> predicate)
{
var domainMerchant = this._repository.GetItemAsync(
predicate.CastParameter<MerchantViewModel, Merchant>());
}
公共异步任务获取(
表达式(谓词)
{
var domainMerchant=this.\u repository.GetItemAsync(
predicate.CastParameter());
}
有关此实现的更多详细信息,请参阅
请注意,此解决方案在使用方面可能会更好,但如果类型不匹配,则会导致运行时错误而不是编译时错误。这实际上使它更容易出错,也不易维护。添加另一个重载或使用通用TW传递替换商户类型方法签名中有
T
?前两个方法返回多个对象。最后一个方法似乎想要返回单个对象。现在还不清楚你在问什么。试着检查一下这一个,这是一个很好的方法,但如果我有XX个类要用这种方法做呢?没有简单的方法?如果这是一个常见的用例,那么为什么有两个不同的模型?为什么不在这两层上使用Merchant
和所有其他类型?因为有不同的视图模型和域模型是一种很好的模式。。tchem之间有一些小的变化。我看到的另一个选择是使用某种转换器,它接受一个表达式
,并从中创建一个表达式
。这可能很难实现,但很容易使用。对于第二种方法,名称应该改进<首先,code>MapParameter会更好,但即使这样,这里也不是真正的情况CastParameter
可能会准确地描述您在这里所做的事情。这就是说,一个简单的泛型约束,其中TFrom:TTo
将确保编译时类型安全。此外,如果提供具有多个参数的lambda,则您的ParameterReplace
将严重失败;名称应该反映这一点,或者它实际上应该替换提供的参数。
public MerchantViewModel : IMerchantFilter
{
public string ExternalId { get; set; }
...
}
public Merchant : IMerchantFilter
{
public string ExternalId { get; set; }
...
}
public class MerchantService : IMerchantService
{
public Task<MerchantViewModel> Get(Expression<Func<IMerchantFilter, bool>> predicate)
{
...
}
...
}
public class MerchantRepository : ...
{
public async Task<IEnumerable<Merchant>> GetItemsAsync(
Expression<Func<IMerchantFilter, bool>> predicate = null)
{
...
}
...
}
using System;
using System.Linq.Expressions;
public static class PredicateMapper
{
public static Expression<Func<TTo, bool>> CastParameter<TFrom, TTo>(
this Expression<Func<TFrom, bool>> predicate)
{
var parameter = Expression.Parameter(typeof(TTo));
var body = new ParameterReplacer<TTo>(parameter).Visit(predicate.Body);
return Expression.Lambda<Func<TTo, bool>>(body, parameter);
}
private class ParameterReplacer<TTo> : ExpressionVisitor
{
private readonly ParameterExpression parameter;
public ParameterReplacer(ParameterExpression parameter)
{
this.parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return this.parameter;
}
protected override Expression VisitMember(MemberExpression node)
{
var matchingMember = typeof(TTo).GetProperty(node.Member.Name);
return Expression.Property(this.Visit(node.Expression), matchingMember);
}
}
}
public async Task<MerchantViewModel> Get(
Expression<Func<MerchantViewModel, bool>> predicate)
{
var domainMerchant = this._repository.GetItemAsync(
predicate.CastParameter<MerchantViewModel, Merchant>());
}