我在泛型和继承方面遇到了一些麻烦。我有一个称为CriteriaBase的抽象类,它的工作是确定实体T是否与任何子类中定义的条件匹配。子类必须实现一种方法,该方法返回代表标准的Func。当我尝试对Func使用泛型时,就会出现问题。希望一些代码可以说明我的问题。

public abstract class CriteriaBase<T, U>
    where T : ICrossoverable
    where U : IChromosome
{
    protected abstract Func<U, bool> Criteria { get; }
    //some code removed for brevity

    private int GetNumberOfCriteriaMatches(T season)
    {
        //1.  works
        //Func<IChromosome, bool> predicate = c => c.Genes == null;
        //return season.Chromosomes.Count(predicate);

        //2.  doesn't work - The type arguments for method 'int
        //System.Linq.Enumerable.Count<TSource>(this IEnumerable<TSource>,
        //Func<TSource, bool>)'
        //cannot be inferred from the usage. Try specifying the type arguments
        //explicitly.
        return season.Chromosomes.Count(Criteria);
    }
}

我的意图是CriteriaBase类应该是通用的并且可以完全重用。

一个示例子类:
public class TopTeamsPlayingEachOtherCriteria : CriteriaBase<Season, MatchDay>
{
    //some code removed for brevity

    protected override Func<MatchDay, bool> Criteria
    {
        get { return matchDay =>
            matchDay.Fixtures.Count(
                fixture =>
                fixture.HomeTeam.TableGrouping.Ordering == 1
                && fixture.AwayTeam.TableGrouping.Ordering == 1) > 1; }
    }
}

问题出在GetNumberOfCriteriaMatches()方法中。选项2是我最初编写代码的方式,但是出现列出的编译错误。如果我使用选项1,则代码会编译,但是这意味着当我在子类中重写Criteria时,必须使用IChromosome而不是MatchDay(这不起作用)(我需要访问MatchDay的特定功能)。在我看来,选项1和2是等效的。选项2只是将IChromosome替换为通用类型U,该类型仅限于实现IChromosome的类。

我正在努力实现的目标有可能吗?如果是这样,我想念/误解了什么?如果没有,我应该如何解决这个问题?

为了完整起见(包括在结尾处,因为我不确定它对问题有多大帮助),以下是我目前用于T(Season)和U(MatchDay)的两个实体。
public class Season : ICrossoverable
{
    private readonly IEnumerable<MatchDay> _matchDays;

    public Season(IEnumerable<MatchDay> matchDays)
    {
        _matchDays = matchDays;
    }

    public IEnumerable<MatchDay> MatchDays
    {
        get { return _matchDays; }
    }

    //ICrossoverable implementation
    public IEnumerable<IChromosome> Chromosomes
    {
        get { return _matchDays; }
    }
}

public class MatchDay : IChromosome
{
    private readonly int _week;
    private readonly List<Fixture> _fixtures;

    public MatchDay(int week, List<Fixture> fixtures)
    {
        _week = week;
        _fixtures = fixtures;
    }

    //some code removed for brevity

    public IEnumerable<Fixture> Fixtures
    {
        get { return _fixtures; }
    }

    //IChromosome implementation
    public IEnumerable<IGene> Genes
    {
        get { return Fixtures; }
    }
}

最佳答案

好吧,这就是问题所在:

public IEnumerable<IChromosome> Chromosomes

您只是在声明要返回的IChromosome值序列。您的条件需要MatchDay值。您碰巧知道它实际上是在返回一个MatchDay值序列,但是编译器却没有。

您可以在执行时使用Cast<>进行检查:
return season.Chromosomes.Cast<U>().Count(Criteria);

...或者您可以更改Chromosomes以返回IEnumerable<MatchDay>。不幸的是,由于我们不知道ICrossoverable的声明方式,我们无法真正判断出这是否是一个有效的答案。也许您应该使ICrossoverable在元素类型中通用?

10-07 13:50