Динамический Func / Lambdas - PullRequest
       9

Динамический Func / Lambdas

0 голосов
/ 11 августа 2011

У меня есть метод, похожий на этот, который перебирает один набор данных и использует значение первого объекта, чтобы найти объект во втором наборе данных:

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 или используя лямбду другого типа, а затем преобразовав метод во что-то, что я мог бы использовать универсальным образом, т.е.

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

В чем я не совсем уверен, так это в том, как я могу построить Func / Predicate / etc и передать его в метод. Помните, что свойство "id" не будет одинаковым для всех свойств SourceT & 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');

1 Ответ

1 голос
/ 11 августа 2011

Вот самая базовая реализация вашей 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...