如何重构具有不同签名但几乎相同的主体的方法?

时间:2012-11-26 11:41:51

标签: c# refactoring

鉴于这种私人方法:

private static IEnumerable<LedgerSummary> FilterLedgers(IList<LedgerSummary> ledgers, List<ExcludedLedgerAccount> excludedLedgerAccounts)
{
    var excludedLedgerEntries = ledgers.Where(x => excludedLedgerAccounts.Any(y => y.LedgerAccount == x.LedgerAccount)).ToList();

    var filteredLedgers = ledgers.Except(excludedLedgerEntries).ToList();

    // do some more filtering

    return filteredLedgers;
}

和这一个:

private static IEnumerable<LedgerPosting> FilterLedgers(IList<LedgerPosting> ledgers, List<ExcludedLedgerAccount> excludedLedgerAccounts)
{
    var excludedLedgerEntries = ledgers.Where(x => excludedLedgerAccounts.Any(y => y.LedgerAccount == x.DistributionAccountLedgerAccount)).ToList();

    var filteredLedgers = ledgers.Except(excludedLedgerEntries).ToList();

    // do some more filtering

    return filteredLedgers;
}

重构它们的最佳方法是什么,以便我不重复方法体中基本相同的逻辑?

之所以不那么直截了当(在我的脑海中),是因为方法签名与List的{​​{1}}取得(并返回) s和其他LedgerSummary,并且每个都有不同的属性名称(映射到LedgerPostings中的相同属性)。

不幸的是,我无法更改这两个类中的任何一个属性或使用通用接口,例如,出于延长此话语的原因!

我知道答案非常简单(所以我提前道歉)但我现在似乎有一个programmer's block

3 个答案:

答案 0 :(得分:3)

尝试这样的事情(现在手头没有VS,可能需要一些调试)

private static IEnumerable<T> FilterLedgers<T> FilterLedgers(
    IList<T> ledgers, 
    List<ExcludedLedgerAccount> excludedLedgerAccounts,
    Func<T, ExcludedLedgerAccount, bool> selector)
{
    var excludedLedgerEntries = ledgers.Where(x => excludedLedgerAccounts.Any(y => selector(x, y)).ToList();

    var filteredLedgers = ledgers.Except(excludedLedgerEntries).ToList();

    // do some more filtering

    return filteredLedgers;
}

并使用它:

IEnumerable<LedgerSummary> result = FilterLedgers<LedgerSummary>(input, exclude, (i, e) => i.LedgerAccount == e.LedgerAccount);

IEnumerable<LedgerPosting> result = FilterLedgers<LedgerSummary>(input, exclude, (i, e) => i.LedgerAccount == e.DistributionAccountLedgerAccount);

答案 1 :(得分:1)

您可以在Any扩展方法中提取您正在使用的谓词:

private static IEnumerable<LedgerSummary> FilterLedgersImpl(IEnumerable<LedgerSummary> ledgers, Func<LedgerSummary, LedgerAccount, bool> predicate)
{
    var excludedLedgerEntries = 
        ledgers
           .Where(x => excludedLedgerAccounts.Any(y => predicate(x, y)))
           .ToList();

    var filteredLedgers = ledgers.Except(excludedLedgerEntries).ToList();

    // do some more filtering

    return filteredLedgers;
}

然后你可以直接使用这个辅助方法:

var list1 = FilderLedgersImpl(ledgers, (x, y) => y.LedgerAccount == x.LedgerAccount);

var list2 = FilderLedgersImpl(ledgers, (x, y) => y.LedgerAccount == x.DistributionAccountLedgerAccount);

答案 2 :(得分:0)

除非LedgerSummary和LedgerPosting共享一个共同的基类来完成你需要的所有工作(在这种情况下你可以使用泛型),否则你无法做太多。

在C ++中,你可以使用模板(甚至是typedef)来获得一个很好的解决方案,但不能在C#或java中使用...除非你想使用代码生成器。