我有一个类似于此的方法,它循环遍历一组数据并使用第一个对象的值来查找第二组数据中的对象:
private void someMethod(IQueryable<RemoteUser> source, IQueryable<LocalUser> targetData) {
// Loop all records in source data
foreach(var u in source) {
// Get keyvalue from source data and use it to find the matching record in targetData
var keyValue = u.id;
var object = from data.Where(o => o.id == keyValue).FirstOrDefault();
...
}
}
我希望通过传递Func或使用其他类型的lambda使其更可重复使用,然后将方法转换为我可以以通用方式使用的方法,即:
private void someMethod<SourceT, TargetT>(IQueryable<SourceT> source, IQueryable<TargetT> targetData) {
....
}
我不确定的是如何构建Func / Predicate / etc并将其传递给方法。请记住,所有SourceT&amp;中的“id”属性都不一样。 TargetT属性。
为了进一步解释,我想要一些我能做到的事情:
someMethod(RemoteUsers,LocalUsers,something here to say 'find the user using the userId property'
);
someMethod(RemoteProducts,LocalProducts,something here to say 'find the user using the productId property'
);
答案 0 :(得分:1)
以下是someMethod
例程的最基本实现:
private void someMethod<S, T, P>(
IQueryable<S> source,
IQueryable<T> target,
Func<S, P> sourceSelector,
Func<T, P> targetSelector)
{
foreach(var s in source)
{
var sp = sourceSelector(s);
var @object = target
.Where(t => targetSelector(t).Equals(sp)).FirstOrDefault();
//...
}
}
此实现保留了原始代码的结构,但这需要付出代价。您正在对数据库进行source.Count() * target.Count()
次查询。使用foreach
时,您需要放弃使用IQueryable<>
。
事实上,无论何时开始使用foreach
编写代码,您都需要问自己是否可以使用LINQ查询来构建和过滤数据,并使foreach
循环只做“最简单” “任务。
以下是如何使该方法更好地工作:
private void someMethod2<S, T, P>(
IQueryable<S> source,
IQueryable<T> target,
Expression<Func<S, P>> sourceSelector,
Expression<Func<T, P>> targetSelector)
{
var query = source
.GroupJoin(
target,
sourceSelector,
targetSelector,
(s, ts) => ts.FirstOrDefault());
foreach(var @object in query)
{
//...
}
}
请注意使用Expression<Func<,>>
而不只是Func<,>
。另请注意GroupJoin
方法调用。