2011-08-11 141 views
0

我有一个方法与此类似,其循环通过一组数据,并使用第一对象的值来查找一个对象中的第二组数据:动态功能/ lambda表达式

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();  
     ... 
    } 

} 

我想,使其更重用通过传递函数功能,或者使用一些其它类型的拉姆达的,然后方法转换的东西,我可以在一个通用的方式使用,即:

private void someMethod<SourceT, TargetT>(IQueryable<SourceT> source, IQueryable<TargetT> targetData) { 
    .... 
} 

我是什么不完全确定的是我可以如何构建一个Func /谓词/等,并将其传递给方法。请记住,所有SourceT属性中的“id”属性都不相同。

为了进一步解释,我想的东西在那里我可以做到这一点:

的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');

回答

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()查询。使用IQueryable<>时,您需要放弃使用foreach。实际上,只要你开始用foreach编写代码,你需要问问自己,你是否可以使用LINQ查询来构建和过滤数据,并使循环只执行“最简单”的任务。

下面是如何使该方法更好地工作:

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

+0

我的源和目标IQueryable数据不是来自同一个数据源,事实上,它甚至不是数据库 - 它来自Web服务。如何调用someMethod外观(P代表什么?) – bugfixr

+0

@Chu - 由于它们来自不同的源,因此不需要使用'IQueryable <>'和表达式。我仍然使用'GroupJoin'方法并尽可能保持你的'foreach'尽可能轻。 'P'只是你加入的属性(或者更确切地说它们的类型)。 – Enigmativity

+0

感谢您的澄清。只是为了理解选择器部分,我将什么传递给someMethod作为我的'sourceSelector'? – bugfixr