2013-04-07 80 views
6

推斷我有泛型和繼承的麻煩。我有一個叫做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的類。

是我想要實現的可能嗎?如果是這樣,我錯過了什麼/誤解?如果不是,我該如何處理這個問題?

爲了完整(包括在最後,因爲我不知道它有多大幫助與問題),這裏是我目前使用的TSeason)和UMatchDay)兩個實體。

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; } 
    } 
} 
+0

什麼版本。你使用的網絡框架? – 2013-04-07 21:46:43

+0

.NET版本4 - 完整版本不是客戶端配置文件。答案根據版本有所不同嗎?如果這很有趣,請使用Visual Studio 2010。 – Stu 2013-04-07 21:57:08

+0

代表協變和反變換在C#中從4.0版開始工作 – 2013-04-08 04:54:40

回答

8

嗯,這就是問題所在:

public IEnumerable<IChromosome> Chromosomes 

宣佈你正在返回IChromosome值的序列。您的標準預計值爲MatchDay碰巧知道它實際上返回了一個值爲MatchDay的序列,但編譯器沒有。

你可以使用Cast<>在執行時進行檢查:

return season.Chromosomes.Cast<U>().Count(Criteria); 

...或者你可以改變Chromosomes返回一個IEnumerable<MatchDay>。不幸的是,我們無法確定這是否是有效的答案,因爲我們不知道ICrossoverable是如何申報的。也許你應該在元素類型中使ICrossoverable通用?

+0

啊哈!這清除了它。我認爲實際的解決方案在於你的最後一句話 - 使'ICrossoverable'通用。我明天會試試這個報告。 – Stu 2013-04-08 22:12:51

+2

正如所建議的,我做了'ICrossoverable'通用解決了我的問題。代碼在[我的Github存儲庫](https://github.com/hungryhippo2312/GeneticAlgorithm)。我將ICrossoverable更名爲IOrganism,因爲它與遺傳算法術語相適應得更好。可以在[另一個Github存儲庫](https://github.com/hungryhippo2312/FixtureGenerator/blob/master/FixtureGenerator/Criteria/SuperSundayCriteria.cs)中找到'CriteriaBase 的實現。感謝您提供多種多樣的建議。 – Stu 2013-04-10 17:16:31

3

您應該在CriteriaBase定義中的U之前使用關鍵字in。事情是這樣的:

public abstract class CriteriaBase<T, in U> 
    where T : ICrossoverable 
    where U : IChromosome 

更新。不起作用。 嘗試指定類型明確

private int GetNumberOfCriteriaMatches(T season) 
{ 
.... 
    return season.Chromosomes.Count<IChromosome>(Criteria); 
} 
+0

當我這樣做時,我得到一個編譯器錯誤,說'變量類型參數只能在接口或委託中聲明'。三個問題:添加「in」是做什麼的,這個錯誤是什麼意思,爲什麼它不起作用?謝謝! – Stu 2013-04-07 21:58:48

+0

我忘記了這隻適用於代表和接口。好。比嘗試明確指定計數(條件) – 2013-04-08 04:59:03

+0

現在有一個不同的錯誤! '參數類型'System.Func '不能分配給參數類型'System.Func '。這幾乎就像'U:IChromosome'不存在!現在在哪裏? – Stu 2013-04-08 06:16:21