2013-04-07 18 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をオーバーライドすると、MatchDayの代わりにIChromosomeを使用する必要があります(MatchDayの特定の機能にアクセスする必要があります)。私の単純な考え方では、オプション1と2は同等です。オプション2は、IChromosomeを、IChromosomeを実装するクラスに制限された汎用タイプUに置き換えるだけです。

達成しようとしていることはありますか?もしそうなら、私は何か不足している/誤解ですか?もしそうでなければ、私はこの問題にどのように接近すべきですか?ここでは完全を期すために

は(私はそれが質問に役立ちますどのくらいかわからないとして末尾に含まれている)、私は現在TSeason)とUのために使用しています2つのエンティティ(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; } 
    } 
} 
+0

のバージョンネットフレームワークを使用していますか? –

+0

.NETバージョン4 - クライアントプロファイルではないフルバージョン。バージョンによって回答は異なりますか?興味深い場合はVisual Studio 2010を使用してください。 – Stu

+0

delegateの共分散とcontravarianceはバージョン4.0からのC#で動作しています –

答えて

8

タイプを指定してくださいさて、これは問題です:

public IEnumerable<IChromosome> Chromosomes 

あなただけあなたがIChromosome値のシーケンスを返していることを宣言しています。あなたの基準はMatchDayの値を期待しています。 は実際にはMatchDayという値のシーケンスを返していることがわかりますが、コンパイラは値を返しません。

あなたは、実行時にこれを確認するためにCast<>を使用することができます。

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

...またはあなたがIEnumerable<MatchDay>を返すようにChromosomesを変更することができます。残念ながら、ICrossoverableがどのように宣言されているかわからないので、有効な回答かどうかは実際には分かりません。おそらく、要素タイプにICrossoverableを汎用化する必要がありますか?

+0

ああ!それはそれをクリアする。私は実際の解決策があなたの最後の文章にあると思う - 「ICrossoverable」ジェネリックにする。私は明日これを試して、報告する。 – Stu

+2

提案したように、私は私の問題を解決する 'ICrossoverable'ジェネリックを作りました。コードは[my Github repository](https://github.com/hungryhippo2312/GeneticAlgorithm)にあります。私はそれが遺伝的アルゴリズムの用語ではるかに良いので、ICrossoverableをIOrganismに改名しました。 'CriteriaBase の実装は[別のGithubリポジトリ](https://github.com/hungryhippo2312/FixtureGenerator/blob/master/FixtureGenerator/Criteria/SuperSundayCriteria.cs)にあります。複数のさまざまな提案をありがとう。 – Stu

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

私はこれを行うと、「バリアント型のパラメータがインタフェースまたは代理人のみで宣言できます」というコンパイラエラーが発生します。 3つの質問:「in」を追加すると、このエラーは何を意味し、なぜ機能しないのでしょうか?ありがとう! – Stu

+0

私はこれがデリゲートとインターフェイスに対してのみ機能することを忘れています。 OK。明示的に指定しようとするよりもCount (基準) –

+0

異なるエラーが発生しました。 '引数型' System.Func 'は、パラメータ型' System.Func 'に割り当てられません。それはほぼ「U:IChromosome」が存在しない場合とほぼ同じです!今どこ? – Stu

関連する問題