我有一段代码可以确保客户的地址与用户界面中的修改同步:
var customerAddresses = customer.CustomerAddresses.Select(x => x.Address);
// add address to customer if it does not already exist
foreach (var addressModel in model.Addresses)
{
// make sure an address matches all properties
Func<Address, bool> addressFilter = x => x.Id == addressModel.Id &&
x.Street.Equals(addressModel.Street, StringComparison.OrdinalIgnoreCase) &&
x.City.Equals(addressModel.City, StringComparison.OrdinalIgnoreCase) &&
x.Province.Equals(addressModel.Province, StringComparison.OrdinalIgnoreCase) &&
x.PostalCode.Equals(addressModel.PostalCode, StringComparison.OrdinalIgnoreCase);
// check if customer already has this address
if (!customerAddresses.Any(addressFilter))
{
// check if address already exists in database
var address = this.DbContext.Addresses.SingleOrDefault(addressFilter);
// add address if it does not exist
if (address == null)
{
address = this.DbContext.Addresses.Add(new Address
{
Street = addressModel.Street,
City = addressModel.City,
Province = addressModel.Province,
PostalCode = addressModel.PostalCode
});
}
}
this.DbContext.CustomerAddresses.Add(new InsuredAddress
{
Customer = customer,
Address = address,
IsPreferred = addressModel.IsPreferred
});
}
然而,我担心每次在循环内创建Func<Address, bool> addressFilter
。有没有办法以这样的方式创建过滤器,它接受参数而不需要每次都重新创建?
答案 0 :(得分:2)
一旦理解了编译器如何处理匿名方法,就更容易看到这个含义。
编译器将创建一些具有任意名称的新时间。它将为该类型提供具有其他任意名称的实例方法。该方法的主体将有效地成为这种匿名方法的主体。
每个已关闭的变量都会有一个实例字段。
将在方法中创建此类型的新实例,并且将通过访问此闭包类的字段来替换已关闭的变量。对这个新类的调用将替换对匿名方法的调用。
因此,基于此转换,您应该能够看到匿名方法只编译一次,无论其在另一种方法中的定义范围如何。
说完所有这些之后,真的不应该出于完全无关的原因以这种方式构建你的程序。首先,您要定义Func
而不是Expression<Func>
,因此过滤器无法转换为在数据库上执行的查询,而是您正在下拉整个Addresses
表格 两次(一次拨打Any
时,一次拨打SingleOrDefault
时,代表每个地址你的模型。那是真的坏。我的意思是,至少,你应该使用Expression
来定义谓词,以便可以在事情的数据库方面,省略对Any
的调用,这样你每个循环只进行一次查询,但老实说,你不应该在中执行多个查询。应该做的是加入两个表,以便在一个大查询中获取整个事物的所有信息,而不是在循环中执行任何查询。
答案 1 :(得分:0)
你在乎什么?
不要误解我的意思 - 但这只是一大堆物体的产生。实时问题将是db执行时间。所以,除非你能在这里描述一个问题,否则你很可能完全处于过早优化阶段。我会接受这样的代码。
答案 2 :(得分:0)
您可以使用列表(customerAddresses)和地址模型(addressModel)作为参数创建一个新方法,返回一个布尔值来替换&#34;任何&#34;。
private bool CheckSync(var customerAddresses, var addressModel)
{
foreach(var item in customerAddresses)
{
if(item.Id != addressModel.Id
|| !item.Street.Equals(addressModel.Street, StringComparison.OrdinalIgnoreCase)
|| !item.City.Equals(addressModel.City, StringComparison.OrdinalIgnoreCase)
|| !item.Province.Equals(addressModel.Province, StringComparison.OrdinalIgnoreCase)
|| !item.PostalCode.Equals(addressModel.PostalCode, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
return true;
}
并且调用此方法而不是&#34;任何&#34;:
// check if customer already has this address
if (!CheckSync(customerAddresses, addressFilter))
{
// ...